3 # Copyright (C) 2024 Free Software Foundation, Inc.
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 3 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17 # Script to auto-correct common spelling mistakes.
20 # $ ./gdb/contrib/spellcheck.sh gdb*
22 scriptdir
=$
(cd "$(dirname "$0")" ||
exit; pwd -P)
23 this_script
=$scriptdir/$
(basename "$0")
25 url
=https
://en.wikipedia.org
/wiki
/Wikipedia
:Lists_of_common_misspellings
/For_machines
26 cache_dir
=$scriptdir/..
/..
/.git
27 cache_file
=wikipedia-common-misspellings.txt
28 dictionary
=$cache_dir/$cache_file
29 local_dictionary
=$scriptdir/common-misspellings.txt
30 cache_file2
=spell-check.pat1
32 # Separators: space, slash, tab, colon, comma.
33 declare -a grep_separators
41 declare -a sed_separators
80 res
=$
(join $grep_or "$@")
87 res
=$
(join $sed_or "$@")
93 echo "usage: $(basename "$0") [--check] <file|dir>+"
116 trap 'rm -f "$files"' EXIT
130 if [ $# -eq -0 ]; then
137 if [ -f "$arg" ]; then
138 arg
=$
(make_absolute
"$arg")
141 elif [ -d "$arg" ]; then
142 arg
=$
(make_absolute
"$arg")
144 find "$arg" -type f
-exec readlink
-e {} \
; \
147 echo "Not a file or directory: $arg"
152 mapfile
-t unique_files \
153 < <(sort -u "$files" \
162 if [ -f "$dictionary" ]; then
168 trap 'rm -f "$webpage"' EXIT
170 # Download web page containing table.
171 wget
$url -O "$webpage"
173 # Extract table from web page.
174 awk '/<pre>/,/<\/pre>/' "$webpage" \
175 |
sed 's/<pre>//;s/<\/pre>//' \
183 output_local_dictionary
()
185 # Filter out comments and empty lines.
191 output_dictionaries
()
193 output_local_dictionary
201 < <(awk -F '->' '{print $1}' <(output_dictionaries
))
202 mapfile
-t replacements \
203 < <(awk -F '->' '{print $2}' <(output_dictionaries
))
206 find_files_matching_words
()
209 cache_id
=$
(cat "$local_dictionary" "$dictionary" "$this_script" \
214 patfile
="$cache_dir/$cache_file2".
$cache_id
217 if [ -f "$patfile" ]; then
218 pat
=$
(cat "$patfile")
220 rm -f "$cache_dir/$cache_file2".
*
222 pat
=$
(grep_join
"${words[@]}")
227 "${grep_separators[@]}")
229 "${grep_separators[@]}" \
233 pat
="$before$pat$after"
245 find_files_matching_word
()
254 "${grep_separators[@]}")
256 "${grep_separators[@]}" \
260 pat
="$before$pat$after"
268 replace_word_in_file
()
282 "${sed_separators[@]}")
284 "${sed_separators[@]}" \
289 repl
="s%$before$word$after%\1$replacement\2%g"
296 replace_word_in_files
()
307 id
="$word -> $replacement"
309 # Reduce set of files for sed to operate on.
310 local files_matching_word
311 declare -a files_matching_word
312 mapfile
-t files_matching_word \
313 < <(find_files_matching_word
"$word" "$@")
315 if [ ${#files_matching_word[@]} -eq 0 ]; then
319 if echo "$replacement"|
grep -q ","; then
326 local changed f before after
328 for f
in "${files_matching_word[@]}"; do
329 if [ "${md5sums[$f]}" = "" ]; then
330 md5sums
[$f]=$
(md5sum "$f")
333 before
="${md5sums[$f]}"
335 replace_word_in_file \
342 if [ "$after" != "$before" ]; then
352 find_files_matching_word
"$word" "${files_matching_word[@]}" \
353 |
awk "{ printf \"TODO: $id: replacement failed: %s\n\", \$0}"
358 declare -a unique_files
365 declare -a replacements
368 # Reduce set of files for sed to operate on.
369 local files_matching_words
370 declare -a files_matching_words
371 mapfile
-t files_matching_words \
372 < <(find_files_matching_words
"${unique_files[@]}")
374 if [ ${#files_matching_words[@]} -eq 0 ]; then
382 declare -A words_done
383 local i word replacement
385 for word
in "${words[@]}"; do
386 replacement
=${replacements[$i]}
389 # Skip words that are already handled. This ensures that the local
390 # dictionary overrides the wiki dictionary.
391 if [ "${words_done[$word]}" == 1 ]; then
396 replace_word_in_files \
399 "${files_matching_words[@]}"