Skip to content

Commit

Permalink
Add tool to verify stringtable entries exist (#6889)
Browse files Browse the repository at this point in the history
* Add tool to verify stringtable entries exist

* Update circle.yml

* test

* Allow running from root directory as well as from inside the tools directory
  • Loading branch information
PabstMirror authored Mar 31, 2019
1 parent c7e6549 commit 3769679
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 3 deletions.
2 changes: 2 additions & 0 deletions addons/common/ACE_Settings.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
class ACE_Settings {
//IGNORE_STRING_WARNING(STR_ACE_Common_SettingName);
//IGNORE_STRING_WARNING(STR_ACE_Common_SettingDescription);
/*
* class GVAR(sampleSetting) {
* value = 1; // Value
Expand Down
2 changes: 1 addition & 1 deletion addons/common/functions/fnc_cbaSettings_convertHelper.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ private _settings = configProperties [configFile >> "ACE_Settings", "(isClass _x
_output pushBack "";
_output pushBack format ["["];
_output pushBack format [" QGVAR(%1), ""%2"",", _gvarName, _cbaSettingType];
_output pushBack format [" [LSTRING(), LSTRING()], // %1, %2", _localizedName, _localizedDescription];
_output pushBack format [" [LSTRING(), LSTRING()], // %1, %2", _localizedName, _localizedDescription]; //IGNORE_STRING_WARNING(str_ace_common_);
_output pushBack format [" ""%1"", // %2", ["localize LSTRING()", _category] select _uncat, _category];
_output pushBack format [" %1, // %2", _cbaValueInfo, _cbaValueInfoHint];
_output pushBack format [" %1, // isGlobal", _cbaIsGlobal];
Expand Down
1 change: 1 addition & 0 deletions addons/repair/functions/fnc_getHitPointString.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ if (_track) then {
};

// Prepare first part of the string from stringtable
//IGNORE_STRING_WARNING(str_ace_repair_hit);
private _text = LSTRING(Hit);

// Remove "Hit" from hitpoint name if one exists
Expand Down
4 changes: 2 additions & 2 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ jobs:
steps:
- checkout
- run:
name: Validate SQF and Config style
command: python tools/sqf_validator.py && python tools/config_style_checker.py
name: Validate SQF and Config style and Stringtable entries
command: python tools/sqf_validator.py && python tools/config_style_checker.py && python tools/check_strings.py

linting:
docker:
Expand Down
101 changes: 101 additions & 0 deletions tools/check_strings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#!/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):
selfmodule = (re.search('addons[\W]*([_a-zA-Z0-9]*)', filepath)).group(1)
# print("Checking {0} from {1}".format(filepath,selfmodule))
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)

srch = re.compile('[^E][CL]STRING\(([_a-zA-Z0-9]*)\)', re.IGNORECASE)
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))

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 = []

# Allow running from root directory as well as from inside the tools directory
rootDir = "../addons"
if (os.path.exists("addons")):
rootDir = "addons"

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))

for filename in fnmatch.filter(filenames, '*.xml'):
xml_list.append(os.path.join(root, filename))

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)))

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)

0 comments on commit 3769679

Please sign in to comment.