2019-03-31 20:27:51 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
# PabstMirror
|
|
|
|
# Checks all strings are defined, run with -u to return all unused strings
|
|
|
|
|
|
|
|
import fnmatch
|
|
|
|
import os
|
|
|
|
import re
|
|
|
|
import sys
|
|
|
|
|
|
|
|
def getDefinedStrings(filepath):
|
|
|
|
# print("getDefinedStrings {0}".format(filepath))
|
|
|
|
with open(filepath, 'r', encoding="latin-1") as file:
|
|
|
|
content = file.read()
|
|
|
|
srch = re.compile('Key ID\=\"(STR_ACE_[_a-zA-Z0-9]*)"', re.IGNORECASE)
|
|
|
|
modStrings = srch.findall(content)
|
|
|
|
modStrings = [s.lower() for s in modStrings]
|
|
|
|
return modStrings
|
|
|
|
|
|
|
|
def getStringUsage(filepath):
|
2021-06-29 18:21:08 +00:00
|
|
|
selfmodule = (re.search('(addons|optionals)[\W]*([_a-zA-Z0-9]*)', filepath)).group(2)
|
2023-09-23 17:40:48 +00:00
|
|
|
submodule = (re.search(f'(addons|optionals)[\W]*{selfmodule}[\W]*([_a-zA-Z0-9]*)', filepath)).group(2)
|
|
|
|
# print(f"Checking {filepath} from {selfmodule} ({submodule})")
|
2019-03-31 20:27:51 +00:00
|
|
|
fileStrings = []
|
|
|
|
|
|
|
|
with open(filepath, 'r') as file:
|
|
|
|
content = file.read()
|
|
|
|
|
|
|
|
srch = re.compile('(STR_ACE_[_a-zA-Z0-9]*)', re.IGNORECASE)
|
|
|
|
fileStrings = srch.findall(content)
|
|
|
|
|
2023-09-23 17:40:48 +00:00
|
|
|
srch = re.compile('[^EB][CL]STRING\(([_a-zA-Z0-9]*)\)', re.IGNORECASE)
|
2019-03-31 20:27:51 +00:00
|
|
|
modStrings = srch.findall(content)
|
|
|
|
for localString in modStrings:
|
|
|
|
fileStrings.append("STR_ACE_{0}_{1}".format(selfmodule, localString))
|
|
|
|
|
|
|
|
srch = re.compile('E[CL]STRING\(([_a-zA-Z0-9]*),([_a-zA-Z0-9]*)\)')
|
|
|
|
exStrings = srch.findall(content)
|
|
|
|
for (exModule, exString) in exStrings:
|
|
|
|
fileStrings.append("STR_ACE_{0}_{1}".format(exModule, exString))
|
|
|
|
|
2023-09-23 17:40:48 +00:00
|
|
|
srch = re.compile('SUB[CL]STRING\(([_a-zA-Z0-9]*)\)')
|
|
|
|
subStrings = srch.findall(content)
|
|
|
|
for (subString) in subStrings:
|
|
|
|
fileStrings.append(f"STR_ACE_{submodule}_{subString}")
|
|
|
|
|
2019-03-31 20:27:51 +00:00
|
|
|
srch = re.compile('IGNORE_STRING_WARNING\([\'"]*([_a-zA-Z0-9]*)[\'"]*\)')
|
|
|
|
ignoreWarnings = srch.findall(content)
|
|
|
|
|
|
|
|
fileStrings = [s.lower() for s in fileStrings]
|
|
|
|
return [s for s in fileStrings if s not in (i.lower() for i in ignoreWarnings)]
|
|
|
|
|
|
|
|
def main(argv):
|
|
|
|
print("### check_strings.py {} ###".format(argv))
|
|
|
|
sqf_list = []
|
|
|
|
xml_list = []
|
|
|
|
|
|
|
|
allDefinedStrings = []
|
|
|
|
allUsedStrings = []
|
|
|
|
|
2021-06-29 18:21:08 +00:00
|
|
|
for folder in ['addons', 'optionals']:
|
|
|
|
# Allow running from root directory as well as from inside the tools directory
|
|
|
|
rootDir = "../" + folder
|
|
|
|
if (os.path.exists(folder)):
|
|
|
|
rootDir = folder
|
2019-03-31 20:27:51 +00:00
|
|
|
|
2021-06-29 18:21:08 +00:00
|
|
|
for root, dirnames, filenames in os.walk(rootDir):
|
|
|
|
for filename in fnmatch.filter(filenames, '*.sqf'):
|
|
|
|
sqf_list.append(os.path.join(root, filename))
|
|
|
|
for filename in fnmatch.filter(filenames, '*.cpp'):
|
|
|
|
sqf_list.append(os.path.join(root, filename))
|
|
|
|
for filename in fnmatch.filter(filenames, '*.hpp'):
|
|
|
|
sqf_list.append(os.path.join(root, filename))
|
|
|
|
for filename in fnmatch.filter(filenames, '*.h'):
|
|
|
|
sqf_list.append(os.path.join(root, filename))
|
2019-03-31 20:27:51 +00:00
|
|
|
|
2021-06-29 18:21:08 +00:00
|
|
|
for filename in fnmatch.filter(filenames, '*.xml'):
|
|
|
|
xml_list.append(os.path.join(root, filename))
|
2019-03-31 20:27:51 +00:00
|
|
|
|
|
|
|
for filename in xml_list:
|
|
|
|
allDefinedStrings = allDefinedStrings + getDefinedStrings(filename)
|
|
|
|
for filename in sqf_list:
|
|
|
|
allUsedStrings = allUsedStrings + getStringUsage(filename)
|
|
|
|
|
|
|
|
allDefinedStrings = list(sorted(set(allDefinedStrings)))
|
|
|
|
allUsedStrings = list(sorted(set(allUsedStrings)))
|
|
|
|
|
2022-05-18 19:36:05 +00:00
|
|
|
if ("str_ace_tagging_name" in allUsedStrings): allUsedStrings.remove("str_ace_tagging_name") # Handle tagging macro
|
|
|
|
|
2019-03-31 20:27:51 +00:00
|
|
|
print("-----------")
|
|
|
|
countUnusedStrings = 0
|
|
|
|
countUndefinedStrings = 0
|
|
|
|
for s in allDefinedStrings:
|
|
|
|
if (not (s in allUsedStrings)):
|
|
|
|
countUnusedStrings = countUnusedStrings + 1;
|
|
|
|
if ("-u" in argv):
|
|
|
|
print("String {} defined but not used".format(s))
|
|
|
|
print("-----------")
|
|
|
|
for s in allUsedStrings:
|
|
|
|
if (not (s in allDefinedStrings)):
|
|
|
|
print("String {} not defined".format(s))
|
|
|
|
countUndefinedStrings = countUndefinedStrings + 1;
|
|
|
|
print("-----------")
|
|
|
|
|
|
|
|
print("Defined Strings:{0} Used Strings:{1}".format(len(allDefinedStrings),len(allUsedStrings)))
|
|
|
|
print("Unused Strings:{0} Undefined Strings:{1}".format(countUnusedStrings,countUndefinedStrings))
|
|
|
|
|
|
|
|
return countUndefinedStrings
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main(sys.argv)
|