fix compile problems with msvc6
[reactos.git] / reactos / tools / rbuild / testsupportcode.cpp
1 /*
2 * Copyright (C) 2005 Casper S. Hornstrup
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18 #include "pch.h"
19 #include <assert.h>
20
21 #include "rbuild.h"
22
23 using std::string;
24 using std::vector;
25
26 TestSupportCode::TestSupportCode ( const Project& project )
27 : project ( project )
28 {
29 }
30
31 TestSupportCode::~TestSupportCode ()
32 {
33 }
34
35 bool
36 TestSupportCode::IsTestModule ( const Module& module )
37 {
38 return module.type == Test;
39 }
40
41 void
42 TestSupportCode::GenerateTestSupportCode ( bool verbose )
43 {
44 for ( size_t i = 0; i < project.modules.size (); i++ )
45 {
46 if ( IsTestModule ( *project.modules[i] ) )
47 {
48 GenerateTestSupportCodeForModule ( *project.modules[i],
49 verbose );
50 }
51 }
52 }
53
54 void
55 TestSupportCode::GenerateTestSupportCodeForModule ( Module& module,
56 bool verbose )
57 {
58 if ( verbose )
59 {
60 printf ( "\nGenerating test support code for %s",
61 module.name.c_str () );
62 }
63
64 WriteHooksFile ( module );
65 WriteStubsFile ( module );
66 WriteStartupFile ( module );
67 }
68
69 string
70 TestSupportCode::GetHooksFilename ( Module& module )
71 {
72 return NormalizeFilename ( Environment::GetIntermediatePath () + SSEP + module.GetBasePath () + SSEP + "_hooks.c" );
73 }
74
75 char*
76 TestSupportCode::WriteStubbedSymbolToHooksFile ( char* buffer,
77 const StubbedComponent& component,
78 const StubbedSymbol& symbol )
79 {
80 buffer = buffer + sprintf ( buffer,
81 " {\"%s\", \"%s\", NULL, NULL, NULL},\n",
82 component.name.c_str (),
83 symbol.newname.c_str () );
84 return buffer;
85 }
86
87 char*
88 TestSupportCode::WriteStubbedComponentToHooksFile ( char* buffer,
89 const StubbedComponent& component )
90 {
91 for ( size_t i = 0; i < component.symbols.size () ; i++ )
92 buffer = WriteStubbedSymbolToHooksFile ( buffer,
93 component,
94 *component.symbols[i] );
95 return buffer;
96 }
97
98 void
99 TestSupportCode::WriteHooksFile ( Module& module )
100 {
101 char* buf;
102 char* s;
103
104 buf = (char*) malloc ( 50*1024 );
105 if ( buf == NULL )
106 throw OutOfMemoryException ();
107
108 s = buf;
109 s = s + sprintf ( s, "/* This file is automatically generated. */\n" );
110 s = s + sprintf ( s, "#include <windows.h>\n" );
111 s = s + sprintf ( s, "#include \"regtests.h\"\n" );
112 s = s + sprintf ( s, "\n" );
113 s = s + sprintf ( s, "_API_DESCRIPTION ExternalDependencies[] =\n" );
114 s = s + sprintf ( s, "{\n" );
115
116 int symbolCount = 0;
117 for ( size_t i = 0; i < module.stubbedComponents.size () ; i++ )
118 {
119 s = WriteStubbedComponentToHooksFile ( s,
120 *module.stubbedComponents[i] );
121 symbolCount += module.stubbedComponents[i]->symbols.size ();
122 }
123
124 s = s + sprintf ( s, "};\n" );
125 s = s + sprintf ( s, "\n" );
126 s = s + sprintf ( s, "#define ExternalDependencyCount %d\n", symbolCount );
127 s = s + sprintf ( s, "ULONG MaxExternalDependency = ExternalDependencyCount - 1;\n" );
128 s = s + sprintf ( s, "\n" );
129
130 FileSupportCode::WriteIfChanged ( buf, GetHooksFilename ( module ) );
131
132 free ( buf );
133 }
134
135 string
136 TestSupportCode::GetStubsFilename ( Module& module )
137 {
138 return NormalizeFilename ( Environment::GetIntermediatePath () + SSEP + module.GetBasePath () + SSEP + "_stubs.S" );
139 }
140
141 string
142 GetImportSymbol ( const StubbedSymbol& symbol )
143 {
144 if (symbol.symbol[0] == '@')
145 return "__imp_" + symbol.symbol;
146 else
147 return "__imp__" + symbol.symbol;
148 }
149
150 char*
151 TestSupportCode::WriteStubbedSymbolToStubsFile ( char* buffer,
152 const StubbedComponent& component,
153 const StubbedSymbol& symbol,
154 int stubIndex )
155 {
156 string importSymbol = GetImportSymbol( symbol );
157 buffer = buffer + sprintf ( buffer,
158 ".globl _%s\n",
159 symbol.symbol.c_str () );
160 buffer = buffer + sprintf ( buffer,
161 ".globl %s\n",
162 importSymbol.c_str () );
163 buffer = buffer + sprintf ( buffer,
164 "_%s:\n",
165 symbol.symbol.c_str () );
166 buffer = buffer + sprintf ( buffer,
167 "%s:\n",
168 importSymbol.c_str () );
169 buffer = buffer + sprintf ( buffer,
170 " pushl $%d\n",
171 stubIndex );
172 buffer = buffer + sprintf ( buffer,
173 " jmp passthrough\n" );
174 buffer = buffer + sprintf ( buffer, "\n" );
175 return buffer;
176 }
177
178 char*
179 TestSupportCode::WriteStubbedComponentToStubsFile ( char* buffer,
180 const StubbedComponent& component,
181 int* stubIndex )
182 {
183 for ( size_t i = 0; i < component.symbols.size () ; i++ )
184 buffer = WriteStubbedSymbolToStubsFile ( buffer,
185 component,
186 *component.symbols[i],
187 (*stubIndex)++ );
188 return buffer;
189 }
190
191 void
192 TestSupportCode::WriteStubsFile ( Module& module )
193 {
194 char* buf;
195 char* s;
196
197 buf = (char*) malloc ( 50*1024 );
198 if ( buf == NULL )
199 throw OutOfMemoryException ();
200
201 s = buf;
202 s = s + sprintf ( s, "/* This file is automatically generated. */\n" );
203 s = s + sprintf ( s, "passthrough:\n" );
204 s = s + sprintf ( s, " call _FrameworkGetHook@4\n" );
205 s = s + sprintf ( s, " test %%eax, %%eax\n" );
206 s = s + sprintf ( s, " je .return\n" );
207 s = s + sprintf ( s, " jmp *%%eax\n" );
208 s = s + sprintf ( s, ".return:\n" );
209 s = s + sprintf ( s, " /* This will most likely corrupt the stack */\n" );
210 s = s + sprintf ( s, " ret\n" );
211 s = s + sprintf ( s, "\n" );
212
213 int stubIndex = 0;
214 for ( size_t i = 0; i < module.stubbedComponents.size () ; i++ )
215 {
216 s = WriteStubbedComponentToStubsFile ( s,
217 *module.stubbedComponents[i],
218 &stubIndex );
219 }
220
221 FileSupportCode::WriteIfChanged ( buf, GetStubsFilename ( module ) );
222
223 free ( buf );
224 }
225
226 string
227 TestSupportCode::GetStartupFilename ( Module& module )
228 {
229 return NormalizeFilename ( Environment::GetIntermediatePath () + SSEP + module.GetBasePath () + SSEP + "_startup.c" );
230 }
231
232 bool
233 TestSupportCode::IsUnknownCharacter ( char ch )
234 {
235 if ( ch >= 'a' && ch <= 'z' )
236 return false;
237 if ( ch >= 'A' && ch <= 'Z' )
238 return false;
239 if ( ch >= '0' && ch <= '9' )
240 return false;
241 return true;
242 }
243
244 string
245 TestSupportCode::GetTestDispatcherName ( string filename )
246 {
247 string filenamePart = ReplaceExtension ( GetFilename ( filename ), "" );
248 if ( filenamePart.length () > 0 )
249 filenamePart[0] = toupper ( filenamePart[0] );
250 for ( size_t i = 1; i < filenamePart.length (); i++ )
251 {
252 if ( IsUnknownCharacter ( filenamePart[i] ) )
253 filenamePart[i] = '_';
254 else
255 filenamePart[i] = tolower ( filenamePart[i] );
256 }
257 return filenamePart + "Test";
258 }
259
260 bool
261 TestSupportCode::IsTestFile ( string& filename ) const
262 {
263 if ( stricmp ( GetFilename ( filename ).c_str (), "setup.c" ) == 0 )
264 return false;
265 return true;
266 }
267
268 void
269 TestSupportCode::GetSourceFilenames ( string_list& list,
270 Module& module ) const
271 {
272 size_t i;
273
274 const vector<File*>& files = module.non_if_data.files;
275 for ( i = 0; i < files.size (); i++ )
276 {
277 if ( !files[i]->IsGeneratedFile () && IsTestFile ( files[i]->name ) )
278 list.push_back ( files[i]->name );
279 }
280 // intentionally make a copy so that we can append more work in
281 // the middle of processing without having to go recursive
282 vector<If*> v = module.non_if_data.ifs;
283 for ( i = 0; i < v.size (); i++ )
284 {
285 size_t j;
286 If& rIf = *v[i];
287 // check for sub-ifs to add to list
288 const vector<If*>& ifs = rIf.data.ifs;
289 for ( j = 0; j < ifs.size (); j++ )
290 v.push_back ( ifs[j] );
291 const vector<File*>& files = rIf.data.files;
292 for ( j = 0; j < files.size (); j++ )
293 {
294 File& file = *files[j];
295 if ( !file.IsGeneratedFile () && IsTestFile ( file.name ) )
296 {
297 list.push_back ( file.name );
298 }
299 }
300 }
301 }
302
303 char*
304 TestSupportCode::WriteTestDispatcherPrototypesToStartupFile ( char* buffer,
305 Module& module )
306 {
307 string_list files;
308 GetSourceFilenames ( files,
309 module );
310 for ( size_t i = 0; i < files.size (); i++ )
311 {
312 buffer = buffer + sprintf ( buffer,
313 "extern void %s(int Command, char *Buffer);\n",
314 GetTestDispatcherName ( files[i] ).c_str () );
315 }
316 buffer = buffer + sprintf ( buffer, "\n" );
317 return buffer;
318 }
319
320 char*
321 TestSupportCode::WriteRegisterTestsFunctionToStartupFile ( char* buffer,
322 Module& module )
323 {
324 buffer = buffer + sprintf ( buffer,
325 "extern void AddTest(TestRoutine Routine);\n" );
326 buffer = buffer + sprintf ( buffer,
327 "\n" );
328
329 buffer = buffer + sprintf ( buffer,
330 "void\n" );
331 buffer = buffer + sprintf ( buffer,
332 "RegisterTests()\n" );
333 buffer = buffer + sprintf ( buffer,
334 "{\n" );
335
336 string_list files;
337 GetSourceFilenames ( files,
338 module );
339 for ( size_t i = 0; i < files.size (); i++ )
340 {
341 buffer = buffer + sprintf ( buffer,
342 "AddTest((TestRoutine)%s);\n",
343 GetTestDispatcherName ( files[i]).c_str () );
344 }
345 buffer = buffer + sprintf ( buffer,
346 "}\n" );
347 buffer = buffer + sprintf ( buffer, "\n" );
348 return buffer;
349 }
350
351 void
352 TestSupportCode::WriteStartupFile ( Module& module )
353 {
354 char* buf;
355 char* s;
356
357 buf = (char*) malloc ( 50*1024 );
358 if ( buf == NULL )
359 throw OutOfMemoryException ();
360
361 s = buf;
362 s = s + sprintf ( s, "/* This file is automatically generated. */\n" );
363 s = s + sprintf ( s, "\n" );
364 s = s + sprintf ( s, "#include <windows.h>\n" );
365 s = s + sprintf ( s, "#include \"regtests.h\"\n" );
366 s = s + sprintf ( s, "\n" );
367 s = WriteTestDispatcherPrototypesToStartupFile ( s,
368 module );
369 s = WriteRegisterTestsFunctionToStartupFile ( s,
370 module );
371 s = s + sprintf ( s, "\n" );
372 s = s + sprintf ( s, "void\n" );
373 s = s + sprintf ( s, "ConsoleWrite(char *Buffer)\n" );
374 s = s + sprintf ( s, "{\n" );
375 s = s + sprintf ( s, " printf(Buffer);\n" );
376 s = s + sprintf ( s, "}\n" );
377 s = s + sprintf ( s, "\n" );
378 s = s + sprintf ( s, "int\n" );
379 s = s + sprintf ( s, "STDCALL\n" );
380 s = s + sprintf ( s, "WinMain(HINSTANCE hInstance,\n" );
381 s = s + sprintf ( s, " HINSTANCE hPrevInstance,\n" );
382 s = s + sprintf ( s, " LPSTR lpszCmdParam,\n" );
383 s = s + sprintf ( s, " int nCmdShow)\n" );
384 s = s + sprintf ( s, "{\n" );
385 s = s + sprintf ( s, " _SetPriorityClass(_GetCurrentProcess(), HIGH_PRIORITY_CLASS);\n" );
386 s = s + sprintf ( s, " _SetThreadPriority(_GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);\n" );
387 s = s + sprintf ( s, " InitializeTests();\n" );
388 s = s + sprintf ( s, " RegisterTests();\n" );
389 s = s + sprintf ( s, " SetupOnce();\n" );
390 s = s + sprintf ( s, " PerformTests(ConsoleWrite, NULL);\n" );
391 s = s + sprintf ( s, " _ExitProcess(0);\n" );
392 s = s + sprintf ( s, " return 0;\n" );
393 s = s + sprintf ( s, "}\n" );
394 s = s + sprintf ( s, "\n" );
395
396 FileSupportCode::WriteIfChanged ( buf, GetStartupFilename ( module ) );
397
398 free ( buf );
399 }