summaryrefslogtreecommitdiffstats
path: root/bin/checkposix
blob: 52aee8b91cf487db1719cd66e7ff16c425adbd13 (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
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
#!/usr/bin/env perl
require 5.003;
use warnings;

#
# Copyright by The HDF Group.
# All rights reserved.
#
# This file is part of HDF5.  The full HDF5 copyright notice, including
# terms governing use, modification, and redistribution, is contained in
# the COPYING file, which can be found at the root of the source code
# distribution tree, or in https://www.hdfgroup.org/licenses.
# If you do not have access to either file, you may request a copy from
# help@hdfgroup.org.
#
# Dana Robinson
# Spring 2019
# (Original by Robb Matzke)
#
# Purpose:  Given the names of C source files this script will print the
#           file name, line number, and function name of any function that
#           doesn't begin with the letter 'h' or 'H' as stipulated by the
#           HDF5 programming style guide.
#
#           Emacs users can run this script as the compile command and
#           use 'next-error' (usually bound to M-`) to find each name
#           violation.

use File::Basename;

# Loop over all files passed to the function
foreach $arg (@ARGV) {

    # Get the filename from the path
    $filename = fileparse($arg);

    # Skip files that don't include H5private.h
    # H5system. has to be inspected by hand since it wraps POSIX files
    #
    # H5detect and H5make_libsettings are created before the library exists
    # so calls that link to function replacements won't work. We'll ignore
    # it here.
    #
    # If a user specifies one file, process it no matter what so people
    # can inspect files we normally skip (like H5system.c).

    $ignore = 0;

    # Ignored files in src/
    if($#ARGV gt 0 and $filename =~ /H5FDmulti|H5FDstdio|H5VLpassthru|H5system|H5detect|H5make_libsettings/) {
        $ignore = 1;
    }
    # Ignored atomic test files in test/
    if($#ARGV gt 0 and $filename =~ /atomic_reader|atomic_writer/) {
        $ignore = 1;
    }
    # Ignored filter plugins in test/
    if($#ARGV gt 0 and $filename =~ /^filter_plugin\d_/) {
        $ignore = 1;
    }
    # Ignored generators in test/
    if($#ARGV gt 0 and $filename =~ /^gen_/) {
        $ignore = 1;
    }

    if($ignore) {
        print "$filename is exempt from using Standard library macro wrappers\n";
        next;
    }

    # Open the file
    open(my $fh, "<", $arg) or do {
        warn "NOTE: Unable to open $arg: !$\n";
        next;
    };

    # Loop over all lines in the file to find undecorated functions
    while (<$fh>) {

        # Get rid of comments by removing the inside part.
        s|/\*.*?\*/||g;
        if ($in_comment) {
            if (/\*\//) {
                s|.*?\*/||;
                $in_comment = 0;
            } else {
                $_="\n";
            }
        } elsif (m|/\*|) {
            s|/\*.*||;
            $in_comment = 1;
        }

        # Get rid of string constants if they begin and end on this line.
        s/([\'\"])([^\1]|\\\1)*?\1/$1$1/g;

        # Get rid of preprocessor directives
        s/^\#.*//;

        # Skip callbacks invoked as methods in a struct
        next if $_ =~ /\b(\)?]?->|\.)\(?([a-z_A-Z]\w*)\s*\(/;

        # Now find all function calls on this line which don't start with 'H'
        while (($name)=/\b([a-z_A-GI-Z]\w*)\s*\(/) {
            $_ = $';
              
            # Ignore C statements that look sort of like function
            # calls.
            next if $name =~ /^(if|for|offsetof|return|sizeof|switch|while|void)$/;

            # Ignore things that get misdetected because of the simplified
            # parsing that takes place here.
            next if $name =~ /^(int|herr_t|_term_interface|_term_package)$/;

            # These are really HDF5 functions/macros even though they don't
            # start with `h' or `H'.
            next if $name =~ /^FUNC_(ENTER|LEAVE)(_(NO)?API|_PACKAGE|_STATIC)?(_NAMECHECK_ONLY|_NOFS|_NOCLEAR|_NOINIT|_NOPUSH)?(_NOFUNC|_TAG)?$/;
            next if $name =~ /^(BEGIN|END)_FUNC$/;
            next if $name =~ /^U?INT(8|16|32|64)(ENCODE|DECODE)(_VAR)?$/;
            next if $name =~ /^CI_(PRINT_STATS|INC_SRC|INC_DST)$/;
            next if $name =~ /^(ABS|ADDR_OVERFLOW|ALL_MEMBERS|BOUND|CONSTR|DETECT_[I|F|M]|DOWN)$/;
            next if $name =~ /^(MIN3?|MAX3?|NELMTS|POWER_OF_TWO|REGION_OVERFLOW)$/;
            next if $name =~ /^(SIZE_OVERFLOW|UNIQUE_MEMBERS|S_ISDIR)$/;
            next if $name =~ /^addr_defined$/;
            next if $name =~ /^TERMINATOR$/;

            # Ignore callback invocation
            next if $name =~ /^(op|cb|OP|iter_op|func)$/;

            # Ignore main
            next if $name =~ /^main$/;

            # This often appears in preprocessor lines that span multiple lines
            next if $name =~ /^(defined)$/;

            # These are Windows system calls. Ignore them.
            next if $name =~ /^(_get_osfhandle|GetFileInformationByHandle|SetFilePointer|GetLastError|SetEndOfFile)$/;
            next if $name =~ /^(FindNextFile|FindClose|_tzset|Wgettimeofday|GetSystemTimeAsFileTime|GetUserName)$/;
            next if $name =~ /^(DeleteCriticalSection|TlsFree|TlsGetValue|CreateThread)$/;
            next if $name =~ /^(ExpandEnvironmentStringsA|LockFileEx|UnlockFileEx)$/;
            next if $name =~ /^(DllMain|LocalAlloc|LocalFree)$/;
            next if $name =~ /^(FindFirstFileA|FindNextFileA)$/;
            next if $name =~ /^(_beginthread|(Initialize|Enter|Leave)CriticalSection|TlsAlloc)$/;

            # These are MPI function calls. Ignore them.
            next if $name =~ /^(MPI_|MPE_)/;

            # These are POSIX threads function calls. Ignore them.
            next if $name =~ /^pthread_/;

            # These are zlib & szlib function calls. Ignore them.
            next if $name =~ /^(inflate|SZ_)/;
            next if $name =~ /^compress2$/;

            # These is an H5Dfill function. Ignore it in this file.
            if($filename =~ /H5Dfill/) {
                next if $name =~ /^(alloc_func)$/;
            }

            # These are H5Zscaleoffset functions. Ignore them in this file.
            if($filename =~ /H5Zscaleoffset/) {
                next if $name =~ /^(pow_fun|round_fun|abs_fun|lround_fun|llround_fun)$/;
            }

            # This is a macro parameter in H5Rint.c. Ignore it in this file.
            if($filename =~ /H5Rint/) {
                next if $name =~ /^(func)$/;
            }

            # Internal calls in the HDFS VFD (H5FDhdfs.c). Ignore it in this file.
            if($filename =~ /H5FDhdfs/) {
                next if $name =~ /^(hdfs)/;
            }

            # Macros, etc. from the mirror VFD (H5FDmirror.c). Ignore in this file.
            if($filename =~ /H5FDmirror/) {
                next if $name =~ /^(LOG)/;
                next if $name =~ /^(BSWAP_64|is_host_little_endian)$/;
            }

            # These are things in H5FDs3comms.c and H5FDros3.c. Ignore them in these files.
            if($filename =~ /H5FDs3comms|H5FDros3/) {
                next if $name =~ /^(curl_|curlwritecallback|gmnow)/;
                next if $name =~ /^(ros3_|ROS3_|S3COMMS_)/;
                next if $name =~ /^(EVP_sha256|SHA256|ISO8601NOW)$/;
            }

            # TESTING (not comprehensive - just noise reduction)
            
            # Test macros and functions (testhdf5.h)
            next if $name =~ /^(AddTest|TestErrPrintf|TestSummary|TestCleanup|TestShutdown)$/;
            next if $name =~ /^(CHECK|CHECK_PTR|CHECK_PTR_NULL|CHECK_PTR_EQ|CHECK_I)$/;
            next if $name =~ /^(VERIFY|VERIFY_STR|VERIFY_TYPE|MESSAGE|ERROR)$/;

            # Test macros and functions (h5test.h)
            next if $name =~ /^(TESTING|PASSED|SKIPPED|PUTS_ERROR|FAIL_PUTS_ERROR|FAIL_STACK_ERROR|TEST_ERROR|AT)$/;
            next if $name =~ /^(GetTestExpress)$/;

            # Ignore functions that start with test_ or check_
            next if $name =~ /^test_/;
            next if $name =~ /^check_/;

            # Ignore functions that start with h5_
            next if $name =~ /^h5_/;

            # Ignore process completed status
            next if $name =~ /(WIFEXITED|WEXITSTATUS|WIFSIGNALED|WTERMSIG|WCOREDUMP|WIFSTOPPED|WSTOPSIG)/;

            # Ignore usage functions
            next if $name =~ /^usage$/;

            # Ignore callbacks
            next if $name =~ /(_cb\d?)$/;

            # Specific tests (not even remotely comprehensive)

            # accum test code
            if($filename =~ /accum/) {
                next if $name =~ /^(accum_)/;
            }

            # cache test code
            if($filename =~ /cache/) {
                next if $name =~ /(_entry|_entries|_cache|_check|_dependency|_status|_op)$/;
                next if $name =~ /^(verify_|smoke_check_|row_major_|col_major_)/;
                next if $name =~ /^(resize_configs_are_equal|CACHE_ERROR)$/
            }

            # Splitter VFD test code. Ignore in vfd.c.
            if($filename =~ /vfd/) {
                next if $name =~ /^(SPLITTER_|splitter_)/;
                next if $name =~ /(_splitter_)/;
                next if $name =~ /^(file_exists)$/;
            }

            # S3 VFD test code. Ignore in ros3.c and s3comms.c.
            # HDFS VFD test code. Ignore in hdfs.c.
            if($filename =~ /ros3|s3comms|hdfs/) {
                next if $name =~ /^(JSVERIFY|JSFAILED_|JSERR_|jserr_|FAIL_)/;
                next if $name =~ /^(curl_)/;
                next if $name =~ /^(S3COMMS_FORMAT_CREDENTIAL|ISO8601NOW|gmnow)$/;
            }

            # VDS test code. Ignore in vds.c.
            if($filename =~ /vds/) {
                next if $name =~ /^(vds_)/;
            }

            print "$filename:$.: $name\n";
        }

    }

    # Close the file
    close($fh);
}

if($#ARGV gt 0) {
    print "\n";
    print "NOTE:\n";
    print "If any files were skipped due to being exempt, you can inspect them manually\n";
    print "by using this script on them one at a time, which will always process the file.\n";
}