SDL/build-scripts/check_stdlib_usage.py

264 lines
5.8 KiB
Python
Executable File

#!/usr/bin/env python3
#
# Simple DirectMedia Layer
# Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
#
# This software is provided 'as-is', without any express or implied
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
#
# Permission is granted to anyone to use this software for any purpose,
# including commercial applications, and to alter it and redistribute it
# freely, subject to the following restrictions:
#
# 1. The origin of this software must not be misrepresented; you must not
# claim that you wrote the original software. If you use this software
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# 2. Altered source versions must be plainly marked as such, and must not be
# misrepresented as being the original software.
# 3. This notice may not be removed or altered from any source distribution.
#
# This script detects use of stdlib function in SDL code
import argparse
import os
import pathlib
import re
import sys
SDL_ROOT = pathlib.Path(__file__).resolve().parents[1]
words = [
'abs',
'acos',
'acosf',
'asin',
'asinf',
'asprintf',
'atan',
'atan2',
'atan2f',
'atanf',
'atof',
'atoi',
'bsearch',
'calloc',
'ceil',
'ceilf',
'copysign',
'copysignf',
'cos',
'cosf',
'crc32',
'exp',
'expf',
'fabs',
'fabsf',
'floor',
'floorf',
'fmod',
'fmodf',
'free',
'getenv',
'isalnum',
'isalpha',
'isblank',
'iscntrl',
'isdigit',
'isgraph',
'islower',
'isprint',
'ispunct',
'isspace',
'isupper',
'isxdigit',
'itoa',
'lltoa',
'log10',
'log10f',
'logf',
'lround',
'lroundf',
'ltoa',
'malloc',
'memalign',
'memcmp',
'memcpy',
'memcpy4',
'memmove',
'memset',
'pow',
'powf',
'qsort',
'qsort_r',
'qsort_s',
'realloc',
'round',
'roundf',
'scalbn',
'scalbnf',
'setenv',
'sin',
'sinf',
'snprintf',
'sqrt',
'sqrtf',
'sscanf',
'strcasecmp',
'strchr',
'strcmp',
'strdup',
'strlcat',
'strlcpy',
'strlen',
'strlwr',
'strncasecmp',
'strncmp',
'strrchr',
'strrev',
'strstr',
'strtod',
'strtokr',
'strtol',
'strtoll',
'strtoul',
'strupr',
'tan',
'tanf',
'tolower',
'toupper',
'trunc',
'truncf',
'uitoa',
'ulltoa',
'ultoa',
'utf8strlcpy',
'utf8strlen',
'vasprintf',
'vsnprintf',
'vsscanf',
'wcscasecmp',
'wcscmp',
'wcsdup',
'wcslcat',
'wcslcpy',
'wcslen',
'wcsncasecmp',
'wcsncmp',
'wcsstr' ]
reg_comment_remove_content = re.compile('\/\*.*\*/')
reg_comment_remove_content2 = re.compile('".*"')
reg_comment_remove_content3 = re.compile(':strlen')
reg_comment_remove_content4 = re.compile('->free')
def find_symbols_in_file(file, regex):
allowed_extensions = [ ".c", ".cpp", ".m", ".h", ".hpp", ".cc" ]
excluded_paths = [
"src/stdlib",
"src/libm",
"src/hidapi",
"src/video/khronos",
"include/SDL3",
"build-scripts/gen_audio_resampler_filter.c",
"build-scripts/gen_audio_channel_conversion.c" ]
filename = pathlib.Path(file)
for ep in excluded_paths:
if ep in filename.as_posix():
# skip
return
if filename.suffix not in allowed_extensions:
# skip
return
# print("Parse %s" % file)
try:
with file.open("r", encoding="UTF-8", newline="") as rfp:
parsing_comment = False
for l in rfp:
l = l.strip()
# Get the comment block /* ... */ across several lines
match_start = "/*" in l
match_end = "*/" in l
if match_start and match_end:
continue
if match_start:
parsing_comment = True
continue
if match_end:
parsing_comment = False
continue
if parsing_comment:
continue
if regex.match(l):
# free() allowed here
if "This should NOT be SDL_" in l:
continue
# double check
# Remove one line comment /* ... */
# eg: extern SDL_DECLSPEC SDL_hid_device * SDLCALL SDL_hid_open_path(const char *path, int bExclusive /* = false */);
l = reg_comment_remove_content.sub('', l)
# Remove strings " ... "
l = reg_comment_remove_content2.sub('', l)
# :strlen
l = reg_comment_remove_content3.sub('', l)
# ->free
l = reg_comment_remove_content4.sub('', l)
if regex.match(l):
print("File %s" % filename)
print(" %s" % l)
print("")
except UnicodeDecodeError:
print("%s is not text, skipping" % file)
except Exception as err:
print("%s" % err)
def find_symbols_in_dir(path, regex):
for entry in path.glob("*"):
if entry.is_dir():
find_symbols_in_dir(entry, regex)
else:
find_symbols_in_file(entry, regex)
def main():
str = ".*\\b("
for w in words:
str += w + "|"
str = str[:-1]
str += ")\("
regex = re.compile(str)
find_symbols_in_dir(SDL_ROOT, regex)
if __name__ == "__main__":
parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
args = parser.parse_args()
try:
main()
except Exception as e:
print(e)
exit(-1)
exit(0)