summaryrefslogtreecommitdiff
path: root/src/contrib/SDL-3.2.20/build-scripts/check_stdlib_usage.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/contrib/SDL-3.2.20/build-scripts/check_stdlib_usage.py')
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/check_stdlib_usage.py262
1 files changed, 262 insertions, 0 deletions
diff --git a/src/contrib/SDL-3.2.20/build-scripts/check_stdlib_usage.py b/src/contrib/SDL-3.2.20/build-scripts/check_stdlib_usage.py
new file mode 100755
index 0000000..0994130
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/check_stdlib_usage.py
@@ -0,0 +1,262 @@
1#!/usr/bin/env python3
2#
3# Simple DirectMedia Layer
4# Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
5#
6# This software is provided 'as-is', without any express or implied
7# warranty. In no event will the authors be held liable for any damages
8# arising from the use of this software.
9#
10# Permission is granted to anyone to use this software for any purpose,
11# including commercial applications, and to alter it and redistribute it
12# freely, subject to the following restrictions:
13#
14# 1. The origin of this software must not be misrepresented; you must not
15# claim that you wrote the original software. If you use this software
16# in a product, an acknowledgment in the product documentation would be
17# appreciated but is not required.
18# 2. Altered source versions must be plainly marked as such, and must not be
19# misrepresented as being the original software.
20# 3. This notice may not be removed or altered from any source distribution.
21#
22# This script detects use of stdlib function in SDL code
23
24import argparse
25import os
26import pathlib
27import re
28import sys
29
30SDL_ROOT = pathlib.Path(__file__).resolve().parents[1]
31
32STDLIB_SYMBOLS = [
33 'abs',
34 'acos',
35 'acosf',
36 'asin',
37 'asinf',
38 'asprintf',
39 'atan',
40 'atan2',
41 'atan2f',
42 'atanf',
43 'atof',
44 'atoi',
45 'bsearch',
46 'calloc',
47 'ceil',
48 'ceilf',
49 'copysign',
50 'copysignf',
51 'cos',
52 'cosf',
53 'crc32',
54 'exp',
55 'expf',
56 'fabs',
57 'fabsf',
58 'floor',
59 'floorf',
60 'fmod',
61 'fmodf',
62 'free',
63 'getenv',
64 'isalnum',
65 'isalpha',
66 'isblank',
67 'iscntrl',
68 'isdigit',
69 'isgraph',
70 'islower',
71 'isprint',
72 'ispunct',
73 'isspace',
74 'isupper',
75 'isxdigit',
76 'itoa',
77 'lltoa',
78 'log10',
79 'log10f',
80 'logf',
81 'lround',
82 'lroundf',
83 'ltoa',
84 'malloc',
85 'memalign',
86 'memcmp',
87 'memcpy',
88 'memcpy4',
89 'memmove',
90 'memset',
91 'pow',
92 'powf',
93 'qsort',
94 'qsort_r',
95 'qsort_s',
96 'realloc',
97 'round',
98 'roundf',
99 'scalbn',
100 'scalbnf',
101 'setenv',
102 'sin',
103 'sinf',
104 'snprintf',
105 'sqrt',
106 'sqrtf',
107 'sscanf',
108 'strcasecmp',
109 'strchr',
110 'strcmp',
111 'strdup',
112 'strlcat',
113 'strlcpy',
114 'strlen',
115 'strlwr',
116 'strncasecmp',
117 'strncmp',
118 'strrchr',
119 'strrev',
120 'strstr',
121 'strtod',
122 'strtokr',
123 'strtol',
124 'strtoll',
125 'strtoul',
126 'strupr',
127 'tan',
128 'tanf',
129 'tolower',
130 'toupper',
131 'trunc',
132 'truncf',
133 'uitoa',
134 'ulltoa',
135 'ultoa',
136 'utf8strlcpy',
137 'utf8strlen',
138 'vasprintf',
139 'vsnprintf',
140 'vsscanf',
141 'wcscasecmp',
142 'wcscmp',
143 'wcsdup',
144 'wcslcat',
145 'wcslcpy',
146 'wcslen',
147 'wcsncasecmp',
148 'wcsncmp',
149 'wcsstr',
150]
151RE_STDLIB_SYMBOL = re.compile(rf"\b(?P<symbol>{'|'.join(STDLIB_SYMBOLS)})\b\(")
152
153
154def find_symbols_in_file(file: pathlib.Path) -> int:
155 match_count = 0
156
157 allowed_extensions = [ ".c", ".cpp", ".m", ".h", ".hpp", ".cc" ]
158
159 excluded_paths = [
160 "src/stdlib",
161 "src/libm",
162 "src/hidapi",
163 "src/video/khronos",
164 "src/video/stb_image.h",
165 "include/SDL3",
166 "build-scripts/gen_audio_resampler_filter.c",
167 "build-scripts/gen_audio_channel_conversion.c",
168 "test/win32/sdlprocdump.c",
169 ]
170
171 filename = pathlib.Path(file)
172
173 for ep in excluded_paths:
174 if ep in filename.as_posix():
175 # skip
176 return 0
177
178 if filename.suffix not in allowed_extensions:
179 # skip
180 return 0
181
182 # print("Parse %s" % file)
183
184 try:
185 with file.open("r", encoding="UTF-8", newline="") as rfp:
186 parsing_comment = False
187 for line_i, original_line in enumerate(rfp, start=1):
188 line = original_line.strip()
189
190 line_comment = ""
191
192 # Get the comment block /* ... */ across several lines
193 while True:
194 if parsing_comment:
195 pos_end_comment = line.find("*/")
196 if pos_end_comment >= 0:
197 line = line[pos_end_comment+2:]
198 parsing_comment = False
199 else:
200 break
201 else:
202 pos_start_comment = line.find("/*")
203 if pos_start_comment >= 0:
204 pos_end_comment = line.find("*/", pos_start_comment+2)
205 if pos_end_comment >= 0:
206 line_comment += line[pos_start_comment:pos_end_comment+2]
207 line = line[:pos_start_comment] + line[pos_end_comment+2:]
208 else:
209 line_comment += line[pos_start_comment:]
210 line = line[:pos_start_comment]
211 parsing_comment = True
212 break
213 else:
214 break
215 if parsing_comment:
216 continue
217 pos_line_comment = line.find("//")
218 if pos_line_comment >= 0:
219 line_comment += line[pos_line_comment:]
220 line = line[:pos_line_comment]
221
222 if m := RE_STDLIB_SYMBOL.match(line):
223 override_string = f"This should NOT be SDL_{m['symbol']}()"
224 if override_string not in line_comment:
225 print(f"{filename}:{line_i}")
226 print(f" {line}")
227 print(f"")
228 match_count += 1
229
230 except UnicodeDecodeError:
231 print(f"{file} is not text, skipping", file=sys.stderr)
232
233 return match_count
234
235def find_symbols_in_dir(path: pathlib.Path) -> int:
236 match_count = 0
237 for entry in path.glob("*"):
238 if entry.is_dir():
239 match_count += find_symbols_in_dir(entry)
240 else:
241 match_count += find_symbols_in_file(entry)
242 return match_count
243
244def main():
245 parser = argparse.ArgumentParser(fromfile_prefix_chars="@")
246 parser.add_argument("path", default=SDL_ROOT, nargs="?", type=pathlib.Path, help="Path to look for stdlib symbols")
247 args = parser.parse_args()
248
249 print(f"Looking for stdlib usage in {args.path}...")
250
251 match_count = find_symbols_in_dir(args.path)
252
253 if match_count:
254 print("If the stdlib usage is intentional, add a '// This should NOT be SDL_<symbol>()' line comment.")
255 print("")
256 print("NOT OK")
257 else:
258 print("OK")
259 return 1 if match_count else 0
260
261if __name__ == "__main__":
262 raise SystemExit(main())