25
25
#include < algorithm>
26
26
#include < array>
27
27
#include < format>
28
+ #include < vector>
29
+ #include < optional>
28
30
29
31
#define NOMINMAX
30
32
#define WIN32_LEAN_AND_MEAN
@@ -36,35 +38,79 @@ int wmain(int argc, wchar_t* argv[])
36
38
{
37
39
SetConsoleOutputCP (CP_UTF8);
38
40
39
- if (argc < 2 )
41
+ struct Arguments
40
42
{
41
- PrintLn (L" Usage: " TOOL_NAME L" <dll_path> [<label:" DEFAULT_LABEL L" >]" );
42
- return 1 ;
43
- }
43
+ std::optional<std::wstring> dll;
44
+ std::optional<std::wstring> label;
45
+ std::vector<std::wstring> ignore;
46
+ } arguments;
44
47
45
- const fs::path dllFilePath = fs::absolute (argv[1 ]);
46
- std::wstring labelName = (argc >= 3 ) ? argv[2 ] : (L" " DEFAULT_LABEL);
48
+ for (int i = 1 ; i < argc; ++i)
49
+ {
50
+ std::wstring_view arg = argv[i];
47
51
48
- if (!fs::exists (dllFilePath) || !fs::is_regular_file (dllFilePath))
52
+ if (arg.length () < 2 || !arg.starts_with (L' -' ))
53
+ continue ;
54
+
55
+ std::wstring key;
56
+ std::wstring value;
57
+
58
+ if (const size_t pos = arg.find_first_of (L' :' , 1 ); pos != std::wstring_view::npos && pos > 1 )
59
+ {
60
+ key = arg.substr (1 , pos - 1 );
61
+ value = arg.substr (pos + 1 );
62
+ }
63
+ else
64
+ {
65
+ key = arg.substr (1 );
66
+ }
67
+
68
+ Trim (key);
69
+ Trim (value);
70
+
71
+ if (key.empty ())
72
+ continue ;
73
+
74
+ if (!_wcsnicmp (key.c_str (), L" dll" , key.size ()))
75
+ {
76
+ if (!value.empty () && !arguments.dll .has_value ())
77
+ arguments.dll = value;
78
+
79
+ continue ;
80
+ }
81
+
82
+ if (!_wcsnicmp (key.c_str (), L" label" , key.size ()))
83
+ {
84
+ if (!value.empty () && !arguments.label .has_value ())
85
+ arguments.label = value;
86
+
87
+ continue ;
88
+ }
89
+
90
+ if (!_wcsnicmp (key.c_str (), L" ignore" , key.size ()))
91
+ {
92
+ if (!value.empty ())
93
+ arguments.ignore .emplace_back (value);
94
+
95
+ continue ;
96
+ }
97
+ }
98
+
99
+ if (!arguments.dll .has_value ())
49
100
{
50
- PrintErrorLn (L" {} is not a regular file " , dllFilePath. wstring () );
101
+ PrintLn (L" Usage: " TOOL_NAME L" -dll:<path> [-label: " DEFAULT_LABEL L" ] [-ignore:<path>] " );
51
102
return 1 ;
52
103
}
53
104
54
- Trim (labelName);
105
+ const fs::path dllFilePath = fs::absolute (arguments.dll .value ());
106
+ std::wstring labelName = arguments.label .value_or (L" " DEFAULT_LABEL);
55
107
56
- if (labelName. empty ( ))
108
+ if (! fs::exists (dllFilePath) || ! fs::is_regular_file (dllFilePath ))
57
109
{
58
- PrintWarningLn (L" 'label' program argument is empty, using " DEFAULT_LABEL );
59
- labelName = ( L" " DEFAULT_LABEL) ;
110
+ PrintErrorLn (L" DLL file '{}' does not exist or is not readable " , dllFilePath. wstring () );
111
+ return 1 ;
60
112
}
61
113
62
- #ifdef MTA_DEBUG
63
- PrintLn (L" [~] " TOOL_NAME L" " TOOL_VERSION);
64
- PrintLn (L" [~] Label: '{}'" , labelName);
65
- PrintLn (L" [~] DLL: '{}'" , dllFilePath.wstring ());
66
- #endif
67
-
68
114
DllAnalyzer dll;
69
115
70
116
if (auto [errorCode, hr] = dll.LoadDll (dllFilePath.wstring ()); errorCode != DllAnalyzer::LoadError::None)
@@ -133,7 +179,13 @@ int wmain(int argc, wchar_t* argv[])
133
179
}
134
180
135
181
#ifdef MTA_DEBUG
136
- PrintLn (L" [~] PDB: '{}'" , pdbFilePath.wstring ());
182
+ PrintLn (L" [~] " TOOL_NAME L" " TOOL_VERSION);
183
+ PrintLn (L" [~] Label: '{}'" , labelName);
184
+ PrintLn (L" [~] DLL: '{}'" , dllFilePath.wstring ());
185
+ PrintLn (L" [~] PDB: '{}'" , pdbFilePath.wstring ());
186
+
187
+ for (const std::wstring& ignore : arguments.ignore )
188
+ PrintLn (L" [~] Ignore: '{}'" , ignore);
137
189
#endif
138
190
139
191
if (!fs::exists (pdbFilePath) || !fs::is_regular_file (pdbFilePath))
@@ -184,11 +236,40 @@ int wmain(int argc, wchar_t* argv[])
184
236
return 1 ;
185
237
}
186
238
187
- const std::vector<PdbAnalyzer::Function>& functions = pdb.GetFunctions ();
239
+ std::vector<PdbAnalyzer::Function>& functions = pdb.GetFunctions ();
188
240
189
241
if (functions.empty ())
190
242
return 0 ;
191
243
244
+ const auto ContainsIgnore = [&ignored = arguments.ignore ](const PdbAnalyzer::Function& f)
245
+ {
246
+ for (const std::wstring& ignore : ignored)
247
+ {
248
+ if (StrStrIW (f.SourceFile .c_str (), ignore.c_str ()) != nullptr )
249
+ return true ;
250
+ }
251
+
252
+ return false ;
253
+ };
254
+
255
+ functions.erase (std::remove_if (std::begin (functions), std::end (functions), ContainsIgnore), std::end (functions));
256
+
257
+ const auto SortBySource = [](const PdbAnalyzer::Function& lhs, const PdbAnalyzer::Function& rhs)
258
+ {
259
+ const auto compare =
260
+ std::lexicographical_compare_three_way (std::begin (lhs.SourceFile ), std::end (lhs.SourceFile ), std::begin (rhs.SourceFile ), std::end (rhs.SourceFile ),
261
+ [](wchar_t a, wchar_t b) { return std::tolower (a) <=> std::tolower (b); });
262
+
263
+ if (std::is_lt (compare))
264
+ return true ;
265
+ if (std::is_gt (compare))
266
+ return false ;
267
+
268
+ return lhs.SourceLine < rhs.SourceLine ;
269
+ };
270
+
271
+ std::sort (std::begin (functions), std::end (functions), SortBySource);
272
+
192
273
int exitCode = 0 ;
193
274
194
275
const auto isOurLabel = [&labelName](const PdbAnalyzer::Label& l) { return l.Name == labelName; };
@@ -200,6 +281,9 @@ int wmain(int argc, wchar_t* argv[])
200
281
201
282
std::vector<std::wstring> problems;
202
283
284
+ if (!hasLabel && !fs::is_regular_file (function.SourceFile ))
285
+ continue ;
286
+
203
287
if (function.Name .starts_with (L" std::" ) || function.Name .starts_with (L' _' ))
204
288
{
205
289
if (!hasLabel)
@@ -246,19 +330,8 @@ int wmain(int argc, wchar_t* argv[])
246
330
if (problems.empty ())
247
331
continue ;
248
332
249
- if (function.SourceFile .empty ())
250
- {
251
- PrintLn (L" " );
252
- PrintLn (L" [>] {}" , function.Name );
253
-
254
- for (const std::wstring& problem : problems)
255
- PrintLn (L" [-] {}" , problem);
256
- }
257
- else
258
- {
259
- for (const std::wstring& problem : problems)
260
- PrintLn (L" {}({}): {}" , function.SourceFile , function.SourceLine , problem);
261
- }
333
+ for (const std::wstring& problem : problems)
334
+ PrintLn (L" {}({}): {}" , function.SourceFile , function.SourceLine , problem);
262
335
}
263
336
264
337
return exitCode;
0 commit comments