summaryrefslogtreecommitdiff
path: root/tools/mpfrlint
blob: 0e87acb306ba1fc074eb0aad3e87edb34447f537 (plain)
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
#!/usr/bin/env bash

# Check possible problems in the MPFR source.

# mpfrlint can be run from the tools directory
dir=`pwd`
[ -d src ] || [ "`basename "$dir"`" != tools ] || cd ..

# 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;
    $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

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 -E "mpfr_(clear|set)_($flaglist) *\(" src/*.{c,h} | \
  grep -v '^src/exceptions.c:' | \
  grep -v '^src/mpfr.h:'

grconf()
{
  grep -v '^dnl ' acinclude.m4 configure.ac | grep -E "$1" && \
    echo "in grconf '$1'"
}

grconf '^(.*if +|[[:space:]]*)(test|\[).* == '
grconf '="`'
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.*'`

grep GMP_LIMB_BITS $srctests

grep GMP_RND $srctests | 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 -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

for i in exp prec rnd
do
  grep mp_${i}_t $srctests | \
    grep -v "\(# *define\|# *ifndef\|typedef\) *mp_${i}_t" | \
    grep -v "\[mp_${i}_t\]"
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
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

# Constant checking should use either MPFR_STAT_STATIC_ASSERT
# or MPFR_ASSERTN(0) for not yet implemented corner cases.
# This test is a heuristic.
# Note: as long as the support of _MPFR_EXP_FORMAT = 4 is not complete,
# run-time assertions involving MPFR_EMAX_MAX, LONG_MAX, etc. should be
# used instead of static assertions to allow testing and correction of
# the code (then the removal of the assertions).
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

# MPFR_ASSERTD or MPFR_ASSERTN must be used for assertions, not ASSERT.
grep -E '[^_]ASSERT *(\(|$)' {src,tests}/*.c

# 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

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"
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:

# 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 ] || \
    grep -q '^# *include *"\(mpfr-impl\|fits.*\|gen_inverse\|random_deviate\)\.h"' $file || \
    echo "Missing '#include \"mpfr-impl.h\"' in $file?"
done

# mpfr_printf-like functions shouldn't be used in the tests,
# as they need <stdarg.h> (HAVE_STDARG defined).
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"
done

# 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 '^\* .*::'

fdlv1="`sed -n '/Version / {
  s/.*Version //
  s/,.*//
  p
  q
  }' doc/fdl.texi`"
fdlv2="`sed -n '/GNU Free Documentation License/ {
  s/.*Version //
  s/ or.*//
  p
  q
  }' doc/mpfr.texi`"
[ "x$fdlv1" = "x$fdlv2" ] || cat <<EOF
GFDL versions differ:
   fdl.texi: $fdlv1
  mpfr.texi: $fdlv2
EOF

tools/ck-copyright-notice
which gcc > /dev/null 2> /dev/null && tools/ck-mparam

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
  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
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
autoconf minimal versions differ:
  README.dev:   $acv1
  acinclude.m4: $acv2
EOF

# In case of problems, one can also skip files or use "grep -v"...
which codespell > /dev/null 2> /dev/null &&
  codespell -q3 -S algorithm2e.sty,algorithms.tex,texinfo.tex \
    AUTHORS BUGS INSTALL NEWS README TODO doc examples $srctests

cd "$dir"
"`dirname -- "$0"`"/check_inits_clears

true