5 using System
.Collections
.Generic
;
7 public static class DllMapVerifier
9 private struct DllImportRef
11 public DllImportRef (string name
, int line
, int column
)
23 private static Dictionary
<string, List
<DllImportRef
>> dll_imports
24 = new Dictionary
<string, List
<DllImportRef
>> ();
25 private static List
<string> ignore_dlls
= new List
<string> ();
26 private static List
<string> config_dlls
= null;
28 public static int Main (string [] args
)
30 LoadConfigDlls (args
[0]);
31 foreach (string file
in args
) {
32 LoadDllImports (file
);
35 return VerifyDllImports (args
[0]) ? 0 : 1;
38 private static bool VerifyDllImports (string configFile
)
40 int total_unmapped_count
= 0;
42 foreach (KeyValuePair
<string, List
<DllImportRef
>> dll_import
in dll_imports
) {
43 int file_unmapped_count
= 0;
44 foreach (DllImportRef dll_import_ref
in dll_import
.Value
) {
45 if (config_dlls
!= null && config_dlls
.Contains (dll_import_ref
.Name
)) {
49 if (file_unmapped_count
++ == 0) {
50 Console
.Error
.WriteLine ("Unmapped DLLs in file: {0}", dll_import
.Key
);
53 Console
.Error
.WriteLine (" + {0} : {1},{2}", dll_import_ref
.Name
,
54 dll_import_ref
.Line
, dll_import_ref
.Column
);
57 total_unmapped_count
+= file_unmapped_count
;
60 if (total_unmapped_count
> 0) {
61 Console
.Error
.WriteLine ();
62 Console
.Error
.WriteLine (" If any DllImport above is explicitly allowed to be unmapped,");
63 Console
.Error
.WriteLine (" add an 'willfully unmapped' comment to the inside of the attribute:");
64 Console
.Error
.WriteLine ();
65 Console
.Error
.WriteLine (" [DllImport (\"libX11.so.6\") /* willfully unmapped */]");
66 Console
.Error
.WriteLine ();
69 if (total_unmapped_count
> 0 && config_dlls
== null) {
70 Console
.Error
.WriteLine ("No config file for DLL mapping was found ({0})", configFile
);
73 return total_unmapped_count
== 0;
76 private static void LoadDllImports (string csFile
)
78 if (csFile
.StartsWith ("-i")) {
79 ignore_dlls
.Add (csFile
.Substring (2));
83 if (Path
.GetExtension (csFile
) == ".cs" && File
.Exists (csFile
)) {
84 List
<DllImportRef
> dll_import_refs
= null;
86 foreach (DllImportRef dll_import
in ParseFileForDllImports (csFile
)) {
87 if (ignore_dlls
.Contains (dll_import
.Name
)) {
91 if (dll_import_refs
== null) {
92 dll_import_refs
= new List
<DllImportRef
> ();
95 dll_import_refs
.Add (dll_import
);
98 if (dll_import_refs
!= null) {
99 dll_imports
.Add (csFile
, dll_import_refs
);
104 private static void LoadConfigDlls (string configFile
)
107 XmlTextReader config
= new XmlTextReader (configFile
);
108 config_dlls
= new List
<string> ();
109 while (config
.Read ()) {
110 if (config
.NodeType
== XmlNodeType
.Element
&&
111 config
.Name
== "dllmap") {
112 string dll
= config
.GetAttribute ("dll");
113 if (!config_dlls
.Contains (dll
)) {
114 config_dlls
.Add (dll
);
122 #region DllImport parser
124 private static StreamReader reader
;
125 private static int reader_line
;
126 private static int reader_col
;
128 private static IEnumerable
<DllImportRef
> ParseFileForDllImports (string file
)
133 using (reader
= new StreamReader (file
)) {
135 bool in_paren
= false;
136 bool in_attr
= false;
137 bool in_dll_attr
= false;
138 bool in_string
= false;
139 bool in_comment
= false;
140 int dll_line
= 1, dll_col
= 1;
141 string dll_string
= null;
142 string dll_comment
= null;
144 while ((c
= (char)reader
.Peek ()) != Char
.MaxValue
) {
147 case '\t': Read (); break;
152 dll_line
= reader_line
;
153 dll_col
= reader_col
;
156 case '(': Read (); in_paren
= true; break;
157 case ')': Read (); in_paren
= false; break;
160 if (dll_string
== null && in_dll_attr
&& in_paren
&& !in_string
) {
166 if ((char)reader
.Peek () == '*') {
168 if (in_dll_attr
&& !in_comment
) {
174 if (in_dll_attr
&& dll_string
!= null && dll_comment
!= "willfully unmapped") {
175 yield return new DllImportRef (dll_string
, dll_line
, dll_col
);
182 if (!in_dll_attr
&& in_attr
&& ReadDllAttribute ()) {
184 } else if (in_dll_attr
&& in_string
) {
185 dll_string
= ReadDllString ();
187 } else if (in_dll_attr
&& in_comment
) {
188 dll_comment
= ReadDllComment ();
199 private static bool ReadDllAttribute ()
213 private static string ReadDllString ()
215 StringBuilder builder
= new StringBuilder (32);
218 if (Char
.IsLetterOrDigit (c
) || c
== '.' || c
== '-' || c
== '_') {
224 return builder
.ToString ();
227 private static string ReadDllComment ()
229 StringBuilder builder
= new StringBuilder ();
230 char lc
= Char
.MaxValue
;
233 if (c
== Char
.MaxValue
|| (c
== '/' && lc
== '*')) {
235 } else if (lc
!= Char
.MaxValue
) {
240 return builder
.ToString ().Trim ();
243 private static char Read ()
245 char c
= (char)reader
.Read ();