-
-
Notifications
You must be signed in to change notification settings - Fork 76
/
make_command.sh
executable file
·338 lines (298 loc) · 10.3 KB
/
make_command.sh
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
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
#!/bin/bash
function mkd {
[[ -d $1 ]] || mkdir -p "$1"
}
function sub:install {
# read options
local flag_error= flag_release=
while [[ $1 == -* ]]; do
local arg=$1; shift
case $arg in
(--release) flag_release=1 ;;
(*) echo "install: unknown option $arg" >&2
flag_error=1 ;;
esac
done
[[ $flag_error ]] && return 1
local src=$1
local dst=$2
mkd "${dst%/*}"
if [[ $src == *.sh ]]; then
local nl=$'\n' q=\' script=$'1i\\\n# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license'
script=$script$nl'/^[[:space:]]*#/d;/^[[:space:]]*$/d'
[[ $flag_release ]] &&
script=$script$nl's/^\([[:space:]]*_ble_base_repository=\)'$q'.*'$q'\([[:space:]]*\)$/\1'${q}release:$dist_git_branch$q'/'
sed "$script" "$src" > "$dst.part" && mv "$dst.part" "$dst"
else
cp "$src" "$dst"
fi
}
function sub:install/help {
printf ' install src dst\n'
}
function sub:dist {
local dist_git_branch=$(git rev-parse --abbrev-ref HEAD)
local tmpdir=ble-$FULLVER
local src
for src in "$@"; do
local dst=$tmpdir${src#out}
sub:install --release "$src" "$dst"
done
[[ -d dist ]] || mkdir -p dist
tar caf "dist/$tmpdir.$(date +'%Y%m%d').tar.xz" "$tmpdir" && rm -r "$tmpdir"
}
function sub:ignoreeof-messages {
(
cd ~/local/build/bash-4.3/po
sed -nr '/msgid "Use \\"%s\\" to leave the shell\.\\n"/{n;s/^[[:space:]]*msgstr "(.*)"[^"]*$/\1/p;}' *.po | while builtin read -r line || [[ $line ]]; do
[[ $line ]] || continue
echo $(printf "$line" exit) # $() は末端の改行を削除するため
done
) >| lib/core-edit.ignoreeof-messages.new
}
function sub:help {
printf '%s\n' \
'usage: make_command.sh SUBCOMMAND args...' \
'' 'SUBCOMMAND' ''
local sub
for sub in $(declare -F | sed -n 's|^declare -[fx]* sub:\([^/]*\)$|\1|p'); do
if declare -f sub:"$sub"/help &>/dev/null; then
sub:"$sub"/help
else
printf ' %s\n' "$sub"
fi
done
printf '\n'
}
#------------------------------------------------------------------------------
# sub:check
function ble/array#push {
while (($#>=2)); do
builtin eval "$1[\${#$1[@]}]=\"\$2\""
set -- "$1" "${@:3}"
done
}
function sub:check/list-command {
# read arguments
local flag_exclude_this= flag_error=
local command=
while (($#)); do
local arg=$1; shift
case $arg in
(--exclude-this)
flag_exclude_this=1 ;;
(-*)
echo "check: unknown option '$arg'" >&2
flag_error=1 ;;
(--)
[[ $1 ]] && command=$1
break ;;
(*)
command=$arg ;;
esac
done
if [[ ! $command ]]; then
echo "check: command name is not specified." >&2
flag_error=1
fi
[[ $flag_error ]] && return 1
local -a options=(--color --exclude=./test --exclude=*.{md,awk})
[[ $flag_exclude_this ]] && ble/array#push options --exclude=./make_command.sh
grc "${options[@]}" "(^|[^-./\${}=])\b$command"'\b([[:space:]|&;<>()`"'\'']|$)'
}
function sub:check/builtin {
echo "--- $FUNCNAME $1 ---"
local command=$1 esc='(\[[ -?]*[@-~])*'
sub:check/list-command --exclude-this "$command" |
grep -Ev "$rex_grep_head([[:space:]]*|[[:alnum:][:space:]]*[[:space:]])#|(\b|$esc)(builtin|function)$esc([[:space:]]$esc)+$command(\b|$esc)" |
grep -Ev "$command(\b|$esc)=" |
grep -Ev "ble\.sh $esc\($esc$command$esc\)$esc"
}
function sub:check/a.txt {
echo "--- $FUNCNAME ---"
grc --color --exclude=./test --exclude=./make_command.sh 'a\.txt|/dev/(pts/|pty)[0-9]*' |
grep -Ev "$rex_grep_head#|[[:space:]]#"
}
function sub:check/bash300bug {
echo "--- $FUNCNAME ---"
# bash-3.0 では local arr=(1 2 3) とすると
# local arr='(1 2 3)' と解釈されてしまう。
grc 'local [a-zA-Z_]+=\(' --exclude=./test --exclude=./make_command.sh
# bash-3.0 では local -a arr=("$hello") とすると
# クォートしているにも拘らず $hello の中身が単語分割されてしまう。
grc 'local -a [[:alnum:]_]+=\([^)]*[\"'\''`]' --exclude=./{test,ext} --exclude=./make_command.sh
# bash-3.0 では "${scalar[@]/xxxx}" は全て空になる
grc '\$\{[a-zA-Z_0-9]+\[[*@]\]/' --exclude=./{text,ext} --exclude=./make_command.sh --exclude=\*.md --color |
grep -v '#D1570'
# bash-3.0 では "..${var-$'hello'}.." は (var が存在しない時) "..'hello'..." になる。
grc '".*\$\{[^{}]*\$'\''([^\\'\'']|\\.)*'\''\}.*"' --exclude={./make_command.sh,memo,\*.md} --color |
grep -v '#D1774'
}
function sub:check/bash301bug-array-element-length {
echo "--- $FUNCNAME ---"
# bash-3.1 で ${#arr[index]} を用いると、
# 日本語の文字数が変になる。
grc '\$\{#[[:alnum:]]+\[[^@*]' --exclude=test | grep -Ev '^([^#]*[[:space:]])?#'
}
function sub:check/bash501-arith-base {
echo "--- $FUNCNAME ---"
# bash-5.1 で $((10#)) の取り扱いが変わった。
grc '\b10#\$' --exclude={test,ChangeLog.md}
}
function sub:check/bash502-patsub_replacement {
echo "--- $FUNCNAME ---"
# bash-5.2 patsub_replacement で ${var/pat/string} の string 中の & が特別な
# 意味を持つ様になったので、特に意識する場合を除いては quote が必要になった。
local esc='(\[[ -?]*[@-~])*'
grc --color '\$\{[[:alnum:]_]+(\[[^][]*\])?//?([^{}]|\{[^{}]*\})+/[^{}"'\'']*([&$]|\\)' --exclude=./test |
sed -E 'h;s/'"$esc"'//g;s/^[^:]*:[0-9]+:[[:space:]]*//
\Z//?\$q/\$Q\}Zd
\Z//?\$__ble_q/\$__ble_Q\}Zd
\Z//?\$_ble_local_q/\$_ble_local_Q\}Zd
\Z/\$\(\([^()]+\)\)\}Zd
\Z/\$'\''([^\\]|\\.)+'\''\}Zd
\Z\$\{[a-zA-Z0-9_]+//(ARR|DICT|PREFIX|NAME)/\$([a-zA-Z0-9_]+|\{[a-zA-Z0-9_#:-]+\})\}Zd
\Z\$\{[a-zA-Z0-9_]+//'\''%[dlcxy]'\''/\$[a-zA-Z0-9_]+\}Zd # src/canvas.sh
\Z#D1738Zd
\Z\$\{_ble_edit_str//\$'\''\\n'\''/\$'\''\\n'\''"\$comment_begin"\}Zd # edit.sh
g'
grc --color '"[^"]*\$\{[[:alnum:]_]+(\[[^][]*\])?//?([^{}]|\{[^{}]*\})+/[^{}"'\'']*"[^"]*([&$]|\\)' --exclude=./test |
sed -E 'h;s/'"$esc"'//g;s/^[^:]*:[0-9]+:[[:space:]]*//
\Z#D1751Zd
g'
}
function sub:check/gawk402bug-regex-check {
echo "--- $FUNCNAME ---"
grc --color '\[\^?\][^]]*\[:[^]]*:\].[^]]*\]' --exclude={test,ext,\*.md} | grep -Ev '#D1709 safe'
}
function sub:check/assign {
echo "--- $FUNCNAME ---"
local command="$1"
grc --color --exclude=./test --exclude=./memo '\$\([^()]' |
grep -Ev "$rex_grep_head#|[[:space:]]#"
}
function sub:check/memo-numbering {
echo "--- $FUNCNAME ---"
grep -ao '\[#D....\]' memo.txt | awk '
function report_error(message) {
printf("memo-numbering: \x1b[1;31m%s\x1b[m\n", message) > "/dev/stderr";
}
!/\[#D[0-9]{4}\]/ {
report_error("invalid number \"" $0 "\".");
next;
}
{
num = $0;
gsub(/^\[#D0+|\]$/, "", num);
if (prev != "" && num != prev - 1) {
if (prev < num) {
report_error("reverse ordering " num " has come after " prev ".");
} else if (prev == num) {
report_error("duplicate number " num ".");
} else {
for (i = prev - 1; i > num; i--) {
report_error("memo-numbering: missing number " i ".");
}
}
}
prev = num;
}
END {
if (prev != 1) {
for (i = prev - 1; i >= 1; i--)
report_error("memo-numbering: missing number " i ".");
}
}
'
sed -n '0,/^[[:space:]]\{1,\}Done/d;/ \* .*\[#D....\]$/d;/^ \* /p' memo.txt
}
# 誤って ((${#arr[@]})) を ((${arr[@]})) などと書いてしまうミス。
function sub:check/array-count-in-arithmetic-expression {
echo "--- $FUNCNAME ---"
grc --exclude=./make_command.sh '\(\([^[:space:]]*\$\{[[:alnum:]_]+\[[@*]\]\}'
}
# unset 変数名 としていると誤って関数が消えることがある。
function sub:check/unset-variable {
echo "--- $FUNCNAME ---"
local esc='(\[[ -?]*[@-~])*'
sub:check/list-command unset --exclude-this |
grep -Ev "unset$esc[[:space:]]$esc-[vf]|$rex_grep_head[[:space:]]*#"
}
function sub:check {
if ! type grc >/dev/null; then
echo 'blesh check: grc not found. grc can be found in github.com:akinomyoga/mshex.git/' >&2
exit
fi
local esc='(\[[ -?]*[@-~])*'
local rex_grep_head="^$esc[[:graph:]]+$esc:$esc[[:digit:]]*$esc:$esc"
# builtin return break continue : eval echo unset は unset しているので大丈夫のはず
#sub:check/builtin 'history'
#sub:check/builtin 'echo'
#sub:check/builtin '(compopt|type|printf)'
sub:check/builtin 'bind'
sub:check/builtin 'read'
sub:check/builtin 'exit'
#sub:check/assign
sub:check/a.txt
sub:check/bash300bug
sub:check/bash301bug-array-element-length
sub:check/bash501-arith-base
sub:check/bash502-patsub_replacement
sub:check/gawk402bug-regex-check
sub:check/array-count-in-arithmetic-expression
sub:check/unset-variable |
sed -E 'h;s/'"$esc"'//g;s/^[^:]*:[0-9]+:[[:space:]]*//
\Zunset _ble_init_(version|arg|exit|command)\bZd
\Zbuiltins1=\(.* unset .*\)Zd
\Zfunction unsetZd
\Zreadonly -f unsetZd
g'
sub:check/memo-numbering
}
#------------------------------------------------------------------------------
function sub:list-functions/help {
printf ' list-functions [-p] files...\n'
}
function sub:list-functions {
local -a files; files=()
local opt_literal=
local i=0 N=$# args; args=("$@")
while ((i<N)); do
local arg=${args[i++]}
if [[ ! $opt_literal && $arg == -* ]]; then
if [[ $arg == -- ]]; then
opt_literal=1
elif [[ $arg == --* ]]; then
printf 'list-functions: unknown option "%s"\n' "$arg" >&2
opt_error=1
elif [[ $arg == -* ]]; then
local j
for ((j=1;j<${#arg};j++)); do
local o=${arg:j:1}
case $o in
(p) opt_public=1 ;;
(*) printf 'list-functions: unknown option "-%c"\n' "$o" >&2
opt_error=1 ;;
esac
done
fi
else
files+=("$arg")
fi
done
if [[ $opt_public ]]; then
local rex_function_name='[^[:space:]()/]*'
else
local rex_function_name='[^[:space:]()]*'
fi
sed -n 's/^[[:space:]]*function \('"$rex_function_name"'\)[[:space:]].*/\1/p' "${files[@]}" | sort -u
}
#------------------------------------------------------------------------------
if (($#==0)); then
sub:help
elif declare -f sub:"$1" &>/dev/null; then
sub:"$@"
else
echo "unknown subcommand '$1'" >&2
builtin exit 1
fi