summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorvlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4>2016-04-08 15:28:59 +0000
committervlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4>2016-04-08 15:28:59 +0000
commit5c8bf561df637053b4b0d3504e634c93128a3236 (patch)
tree6d3850aefe7b1f07b2e27ce48f4fdf0c1e817bf4 /tools
parent9df4283f8be36e42017db0aa5159c726cf502887 (diff)
downloadmpfr-5c8bf561df637053b4b0d3504e634c93128a3236.tar.gz
[tools/mpfrlint]
* Switched to zsh. * Much more meaningful error messages. * Fix: in the mpfr.texi punctuation test, ignore the comments. git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@10256 280ebfd0-de03-0410-8827-d642c229c3f4
Diffstat (limited to 'tools')
-rwxr-xr-xtools/mpfrlint223
1 files changed, 171 insertions, 52 deletions
diff --git a/tools/mpfrlint b/tools/mpfrlint
index 80099ebe9..830263a11 100755
--- a/tools/mpfrlint
+++ b/tools/mpfrlint
@@ -1,36 +1,129 @@
-#!/usr/bin/env bash
+#!/usr/bin/env zsh
# Check possible problems in the MPFR source.
+set -e
+setopt EXTENDED_GLOB
+
# mpfrlint can be run from the tools directory
-dir=`pwd`
-[ -d src ] || [ "`basename "$dir"`" != tools ] || cd ..
+dir=$PWD
+[[ -d src ]] || [[ $dir:t != tools ]] || cd ..
+err=0
+
+if [[ -t 1 ]] then
+ term=1
+ pfx=""
+ sfx=""
+fi
+
+err-if-output()
+{
+ local dir checkoutput=1 checkstatus=1 output st h line
+ while [[ $1 = -* ]]
+ do
+ case $1 in
+ --dir=*)
+ dir=${1#--dir=} ;;
+ -o)
+ # The command generates output even in case of success;
+ # do not regard this as an error.
+ checkoutput="" ;;
+ -t)
+ # The command normally returns with a non-zero exit status;
+ # do not regard this as an error.
+ checkstatus="" ;;
+ *)
+ echo "unrecognized option '$1' for $0" >&2
+ exit 1 ;;
+ esac
+ shift
+ done
+ [[ -n $dir ]] && pushd $dir
+ set +e
+ output=(${(f)"$($@[2,-1] 2>&1)"})
+ st=$?
+ if [[ ( -n "$checkstatus" && $st -ne 0 ) ||
+ ( -n "$checkoutput" && -n "$output" ) ]] then
+ if [[ -n "$1" && -t 1 ]] then
+ [[ -n "$pfx" ]] || pfx=$(tput 2>/dev/null bold)
+ [[ -n "$sfx" ]] || sfx=$(tput 2>/dev/null sgr0)
+ fi
+ h=${1:+$pfx$1:$sfx }
+ for line in ${output:-"exit status = $st"}
+ do
+ printf "%s%s\n" $h $line
+ done
+ err=1
+ fi
+ set -e
+ [[ -n $dir ]] && popd
+}
+
+if [[ $1 = test ]] then
+ export LC_ALL=C
+ err-if-output Err-e exit 17
+ err-if-output Err-f false
+ err-if-output Err-t true
+ err-if-output "" echo "Empty first argument"
+ err-if-output "1 line" echo foo
+ err-if-output "2 lines" printf "foo\nbar\n"
+ err-if-output -o Err-f false
+ err-if-output -o Err-t true
+ err-if-output -o "cp test" cp
+ err-if-output -o "1 line" echo foo
+ err-if-output -t Err-f false
+ err-if-output -t Err-t true
+ err-if-output -t error echo output
+ echo "Test done."
+ exit
+: <<EOF
+The output should be:
+
+Err-e: exit status = 17
+Err-f: exit status = 1
+Empty first argument
+1 line: foo
+2 lines: foo
+2 lines: bar
+Err-f: exit status = 1
+cp test: cp: missing file operand
+cp test: Try 'cp --help' for more information.
+error: output
+Test done.
+
+EOF
+fi
+
+############################################################################
# Detect the possible use of forbidden macros in mpfr.h, such as those
# starting with "HAVE_" or "WANT_". Public macros defined by MPFR must
# start with "MPFR_".
-perl -ne '/^#/ && ! /^# *error / or next; while (/\b([_A-Z]+)\b/g)
- { my $m = $1;
+err-if-output -t "" perl -ne '
+ /^#/ && ! /^# *error / or next; while (/\b([_A-Z]+)\b/g) {
+ my $m = $1;
$m =~ /^(_*MPFR_|_*GMP_|__(GNUC|ICC|STDC)(_|$)|_MSC_|U?INTMAX_C$)/
and next;
print "Forbidden macro in mpfr.h line $.: $m\n" }' src/mpfr.h
-grep '^# *include *<math\.h>' src/*.c
+err-if-output -t "math.h" grep '^# *include *<math\.h>' src/*.c
flaglist="underflow|overflow|divby0|nanflag|inexflag|erangeflag"
grep -E "mpfr_($flaglist)_p" src/*.{c,h} | \
grep -v -i 'mpfr_clear_' | \
grep -v '^src/exceptions.c:' | \
grep -v '^src/mpfr-impl.h:#define mpfr_.*_p()' | \
- grep -v '^src/mpfr.h:__MPFR_DECLSPEC '
+ grep -v '^src/mpfr.h:__MPFR_DECLSPEC ' | \
+ err-if-output "flags" cat
grep -E "mpfr_(clear|set)_($flaglist) *\(" src/*.{c,h} | \
grep -v '^src/exceptions.c:' | \
- grep -v '^src/mpfr.h:'
+ grep -v '^src/mpfr.h:' | \
+ err-if-output "flags" cat
grconf()
{
- grep -v '^dnl ' acinclude.m4 configure.ac | grep -E "$1" && \
- echo "in grconf '$1'"
+ grep -v '^dnl ' acinclude.m4 configure.ac | \
+ err-if-output -t "grconf '$1'" grep -E "$1"
}
grconf '^(.*if +|[[:space:]]*)(test|\[).* == '
@@ -39,49 +132,55 @@ grconf '[^a-z][ef]?grep[^a-z]'
grconf '[^a-z]sed[^a-z]'
# Note: In the source, ignore everything related to mini-gmp.
-srctests=`find src tests -name '*.[ch]' ! -name '*mini-gmp.*'`
+srctests=({src,tests}/**/*.[ch]~*mini-gmp.*)
+#srctests=(`find src tests -name '*.[ch]' ! -name '*mini-gmp.*'`)
-grep GMP_LIMB_BITS $srctests
+err-if-output -t "GMP_LIMB_BITS" grep GMP_LIMB_BITS $srctests
-grep GMP_RND $srctests | grep -v '#define GMP_RND'
+grep GMP_RND $srctests | err-if-output -t "GMP_RND*" grep -v '#define GMP_RND'
# Note: exceptions __gmpn_rootrem and __gmpn_sbpi1_divappr_q
# are normally used only if WANT_GMP_INTERNALS is defined.
grep '__gmp[nz]_' $srctests | \
grep -v __gmpn_rootrem | \
- grep -v __gmpn_sbpi1_divappr_q
+ grep -v __gmpn_sbpi1_divappr_q | \
+ err-if-output "GMP internals" cat
-grep -E 'mp_(src)?ptr' $srctests
+err-if-output -t "mp_ptr and mp_srcptr" grep -E 'mp_(src)?ptr' $srctests
# Do not use __mpfr_struct structure members in .c files.
-grep -E '[^0-9a-z_]_mpfr_(prec|sign|exp|d)' {src,tests}/*.c
+err-if-output -t "__mpfr_struct members" \
+ grep -E '[^0-9a-z_]_mpfr_(prec|sign|exp|d)' {src,tests}/*.c
# Detect some uses of "x != x" and "x == x". If this occurs in source code,
# x is probably a native FP number (otherwise the test is useless), but in
# such a case, the DOUBLE_ISNAN macro should be used.
-grep '( *\([^[:space:]]*\) *[!=]= *\1 *)' $srctests
+err-if-output -t "x != x and x == x tests" \
+ grep '( *\([^[:space:]]*\) *[!=]= *\1 *)' $srctests
for i in exp prec rnd
do
grep "[^a-z]mp_${i}_t" $srctests | \
grep -v "\(# *define\|# *ifndef\|typedef\) *mp_${i}_t" | \
- grep -v "\[mp_${i}_t\]"
+ grep -v "\[mp_${i}_t\]" | \
+ err-if-output "mp_*_t" cat
done
for file in $srctests
do
- perl -e 'my $f = do { local $/; <> };
- while ($f =~ /MPFR_LOG_MSG\s*\(\s*\(.*?\)\s*\)/gs) {
- my $s = $&; print "$ARGV: $s\n" if
- index($s,"\\n\"") < 0 || $s !~ /"\s*,/
- }' $file
+ err-if-output "MPFR_LOG_MSG format" perl -e '
+ my $f = do { local $/; <> };
+ while ($f =~ /MPFR_LOG_MSG\s*\(\s*\(.*?\)\s*\)/gs) {
+ my $s = $&; print "$ARGV: $s\n" if
+ index($s,"\\n\"") < 0 || $s !~ /"\s*,/
+ }' $file
done
# Do not use snprintf as it is not available in ISO C90.
# Even on platforms where it is available, the prototype
# may not be included (e.g. with gcc -ansi), so that the
# code may be compiled incorrectly.
-grep '[^a-z_]snprintf *([^)]' $srctests
+err-if-output -t "snprintf" grep '[^a-z_]snprintf *([^)]' $srctests
# Constant checking should use either MPFR_STAT_STATIC_ASSERT
# or MPFR_ASSERTN(0) for not yet implemented corner cases.
@@ -93,43 +192,46 @@ grep '[^a-z_]snprintf *([^)]' $srctests
grep 'MPFR_ASSERT[DN][^a-z]*;' src/*.c | grep -v 'MPFR_ASSERTN *(0)' | \
grep -v '\(MPFR_EMAX_MAX\|MPFR_EXP_MAX\).*LONG_MAX' | \
grep -v '\(MPFR_EMIN_MIN\|MPFR_EXP_MIN\).*LONG_MIN' | \
- grep -v MPFR_BLOCK_EXCEP
+ grep -v MPFR_BLOCK_EXCEP | \
+ err-if-output -t "Constant checking" cat
# ASSERT and ASSERT_ALWAYS must not be used for assertion checking.
# Use MPFR_STAT_STATIC_ASSERT for static assertions, otherwise either
# MPFR_ASSERTD (debug mode / hint for the compiler) or MPFR_ASSERTN.
-grep -E '[^_]ASSERT(_ALWAYS)? *(\(|$)' {src,tests}/*.c
+err-if-output -t "ASSERT / ASSERT_ALWAYS" \
+ grep -E '[^_]ASSERT(_ALWAYS)? *(\(|$)' {src,tests}/*.c
# Use MPFR_TMP_LIMBS_ALLOC.
-grep 'MPFR_TMP_ALLOC.*\(BYTES_PER_MP_LIMB\|sizeof.*mp_limb_t\)' src/*.c
+err-if-output -t "Use MPFR_TMP_LIMBS_ALLOC" \
+ grep 'MPFR_TMP_ALLOC.*\(BYTES_PER_MP_LIMB\|sizeof.*mp_limb_t\)' src/*.c
# Use simple mp_limb_t constants: MPFR_LIMB_ZERO, MPFR_LIMB_ONE, etc.
# possibly except in MPFR_STAT_STATIC_ASSERT
grep '(mp_limb_t) *-\?[01]' $srctests | grep -v '#define MPFR_LIMB_' | \
- grep -v MPFR_STAT_STATIC_ASSERT
+ err-if-output -t "Use simple mp_limb_t constants" \
+ grep -v MPFR_STAT_STATIC_ASSERT
for file in $srctests */Makefile.am acinclude.m4 configure.ac
do
# Note: this is one less that the POSIX minimum limit in case
# implementations are buggy like POSIX examples. :)
- perl -ne "/.{2047,}/ and print \
- \"Line \$. of file '$file' has more than 2046 bytes.\n\"" "$file"
+ err-if-output "" perl -ne "/.{2047,}/ and print \
+ \"Line \$. of file $file has more than 2046 bytes.\n\"" "$file"
done
# Code style: a sign decimal constant for mpfr_set_inf and mpfr_set_zero
# should be either 1 or -1 (except for the tests in tset.c).
grep -E 'mpfr_set_(inf|zero) *\([^,]*, *[-+]?([02-9]|1[^)])' $srctests | \
- grep -v tests/tset\\.c:
+ err-if-output -t "mpfr_set_(inf|zero) second argument" \
+ grep -v tests/tset\\.c:
# In general, one needs to include mpfr-impl.h (note that some platforms
# such as MS Windows use a config.h, which is included by mpfr-impl.h).
for file in src/*.c
do
- [ "$file" = src/jyn_asympt.c ] || \
- [ "$file" = src/mini-gmp.c ] || \
- [ "$file" = src/round_raw_generic.c ] || \
+ [[ "$file" = src/(jyn_asympt|mini-gmp|round_raw_generic).c ]] || \
grep -q '^# *include *"\(mpfr-impl\|fits.*\|gen_inverse\|random_deviate\)\.h"' $file || \
- echo "Missing '#include \"mpfr-impl.h\"' in $file?"
+ { echo "Missing '#include \"mpfr-impl.h\"' in $file?" && err=1 }
done
# mpfr_printf-like functions shouldn't be used in the tests,
@@ -138,19 +240,24 @@ for file in tests/*.c
do
sed '/#if\(def\| *defined *(\)\? *HAVE_STDARG/,/#\(endif\|else\) .*HAVE_STDARG/d
/\/\*.*\*\//d
- /\/\*/,/\*\//d' $file | grep -q "mpfr_[a-z]*printf" && \
- echo "$file contains unprotected mpfr_printf-like function calls"
+ /\/\*/,/\*\//d' $file | \
+ err-if-output -t "unprotected mpfr_printf-like function call in $file" \
+ grep "mpfr_[a-z]*printf"
done
-grep __gmp_ tests/*.c | grep -v '^tests/tabort_defalloc'
-grep -E '[^a-z_](m|re)alloc *\(' tests/*.c | grep -v '^tests/memory.c:'
+grep __gmp_ tests/*.c | \
+ err-if-output -t "__gmp_" grep -v '^tests/tabort_defalloc'
+
+grep -E '[^a-z_](m|re)alloc *\(' tests/*.c | \
+ err-if-output -t "alloc" grep -v '^tests/memory.c:'
# Check a Texinfo rule (Section "Ending a Sentence") with common words
# that end with a capital letter:
# Use '@.' instead of a period, '@!' instead of an exclamation point,
# and '@?' instead of a question mark at the end of a sentence that
# does end with a capital letter.
-grep -E '(LIP|MPFR?|NaN)\)?[.!?]' doc/mpfr.texi | grep -v '^\* .*::'
+grep -E '(LIP|MPFR?|NaN)\)?[.!?]' doc/mpfr.texi | \
+ err-if-output -t "mpfr.texi punctuation" grep -Ev '^(\* .*::|@c )'
fdlv1="`sed -n '/Version / {
s/.*Version //
@@ -164,28 +271,33 @@ fdlv2="`sed -n '/GNU Free Documentation License/ {
p
q
}' doc/mpfr.texi`"
-[ "x$fdlv1" = "x$fdlv2" ] || cat <<EOF
+[[ $fdlv1 = $fdlv2 ]] || { cat <<EOF && err=1 }
GFDL versions differ:
fdl.texi: $fdlv1
mpfr.texi: $fdlv2
EOF
tools/ck-copyright-notice
-which gcc > /dev/null 2> /dev/null && tools/ck-mparam
+
+if which gcc > /dev/null 2> /dev/null; then
+ tools/ck-mparam
+else
+ echo "Warning! gcc is not installed. Cannot run ck-mparam." >&2
+fi
texisvnd=`LC_ALL=C TZ=UTC svn info doc/mpfr.texi 2> /dev/null | sed -n 's/Last Changed Date:.*, [0-9]* \([A-Z][a-z][a-z] [0-9][0-9][0-9][0-9]\)).*/\1/p'`
-if [ $? -eq 0 ] && [ -n "$texisvnd" ]; then
+if [[ $? -eq 0 ]] && [[ -n "$texisvnd" ]] then
texidate=`sed -n 's/@set UPDATED-MONTH \([A-Z][a-z][a-z]\).*\( [0-9][0-9][0-9][0-9]\)/\1\2/p' doc/mpfr.texi`
- [ "$texidate" = "$texisvnd" ] || cat <<EOF
+ [[ $texidate = $texisvnd ]] || { cat <<EOF && err=1 }
mpfr.texi's UPDATED-MONTH seems to be incorrect:
mpfr.texi's UPDATED-MONTH: $texidate
Last Changed Date in WC: $texisvnd
EOF
fi
-acv1="`sed -n 's/.*autoconf \([0-9.]\+\) (at least).*/\1/p' doc/README.dev`"
-acv2="`sed -n 's/AC_PREREQ(\([0-9.]\+\).*/\1/p' acinclude.m4`"
-[ "x$acv1" = "x$acv2" ] || cat <<EOF
+acv1=`sed -n 's/.*autoconf \([0-9.]\+\) (at least).*/\1/p' doc/README.dev`
+acv2=`sed -n 's/AC_PREREQ(\([0-9.]\+\).*/\1/p' acinclude.m4`
+[[ $acv1 = $acv2 ]] || { cat <<EOF && err=1 }
autoconf minimal versions differ:
README.dev: $acv1
acinclude.m4: $acv2
@@ -195,11 +307,18 @@ EOF
# In particular, skip the openout.* files, which are created by "make pdf"
# (they are in the doc/mpfr.t2p/mpfr.t2d/pdf/check_recorder directory, and
# unfortunately codespell can't skip directories such as mpfr.t2p).
-which codespell > /dev/null 2> /dev/null &&
- codespell -q3 -S 'algorithm2e.sty,algorithms.tex,texinfo.tex,openout.*' \
+if which codespell > /dev/null 2> /dev/null; then
+ err-if-output "codespell" codespell ${term:+--enable-colors} -q3 -S \
+ 'algorithm2e.sty,algorithms.tex,texinfo.tex,openout.*' \
AUTHORS BUGS INSTALL NEWS README TODO doc examples $srctests
+else
+ echo "Warning! codespell is not installed. Cannot check spelling." >&2
+fi
+
+cd $dir
+$0:h/check_inits_clears
-cd "$dir"
-"`dirname -- "$0"`"/check_inits_clears
+############################################################################
-true
+[[ $err -eq 0 ]] || echo "Terminated with errors." >&2
+exit $err