Copy wininet to branch
[reactos.git] / reactos / tools / rbuild / project.cpp
1
2 #include "pch.h"
3 #include <assert.h>
4
5 #include "rbuild.h"
6
7 using std::string;
8 using std::vector;
9
10 Project::Project ( const string& filename )
11 : xmlfile (filename),
12 node (NULL),
13 head (NULL)
14 {
15 ReadXml();
16 }
17
18 Project::~Project ()
19 {
20 size_t i;
21 for ( i = 0; i < modules.size (); i++ )
22 delete modules[i];
23 for ( i = 0; i < linkerFlags.size (); i++ )
24 delete linkerFlags[i];
25 for ( i = 0; i < cdfiles.size (); i++ )
26 delete cdfiles[i];
27 for ( i = 0; i < installfiles.size (); i++ )
28 delete installfiles[i];
29 delete head;
30 }
31
32 const Property*
33 Project::LookupProperty ( const string& name ) const
34 {
35 for ( size_t i = 0; i < non_if_data.properties.size (); i++ )
36 {
37 const Property* property = non_if_data.properties[i];
38 if ( property->name == name )
39 return property;
40 }
41 return NULL;
42 }
43
44 void
45 Project::WriteIfChanged ( char* outbuf,
46 string filename )
47 {
48 FILE* out;
49 unsigned int end;
50 char* cmpbuf;
51 unsigned int stat;
52
53 out = fopen ( filename.c_str (), "rb" );
54 if ( out == NULL )
55 {
56 out = fopen ( filename.c_str (), "wb" );
57 if ( out == NULL )
58 throw AccessDeniedException ( filename );
59 fputs ( outbuf, out );
60 fclose ( out );
61 return;
62 }
63
64 fseek ( out, 0, SEEK_END );
65 end = ftell ( out );
66 cmpbuf = (char*) malloc ( end );
67 if ( cmpbuf == NULL )
68 {
69 fclose ( out );
70 throw OutOfMemoryException ();
71 }
72
73 fseek ( out, 0, SEEK_SET );
74 stat = fread ( cmpbuf, 1, end, out );
75 if ( stat != end )
76 {
77 free ( cmpbuf );
78 fclose ( out );
79 throw AccessDeniedException ( filename );
80 }
81 if ( end == strlen ( outbuf ) && memcmp ( cmpbuf, outbuf, end ) == 0 )
82 {
83 free ( cmpbuf );
84 fclose ( out );
85 return;
86 }
87
88 free ( cmpbuf );
89 fclose ( out );
90 out = fopen ( filename.c_str (), "wb" );
91 if ( out == NULL )
92 {
93 throw AccessDeniedException ( filename );
94 }
95
96 stat = fwrite ( outbuf, 1, strlen ( outbuf ), out);
97 if ( strlen ( outbuf ) != stat )
98 {
99 fclose ( out );
100 throw AccessDeniedException ( filename );
101 }
102
103 fclose ( out );
104 }
105
106 void
107 Project::SetConfigurationOption ( char* s,
108 string name,
109 string* alternativeName )
110 {
111 const Property* property = LookupProperty ( name );
112 if ( property != NULL && property->value.length () > 0 )
113 {
114 s = s + sprintf ( s,
115 "#define %s=%s\n",
116 property->name.c_str (),
117 property->value.c_str () );
118 }
119 else if ( property != NULL )
120 {
121 s = s + sprintf ( s,
122 "#define %s\n",
123 property->name.c_str () );
124 }
125 else if ( alternativeName != NULL )
126 {
127 s = s + sprintf ( s,
128 "#define %s\n",
129 alternativeName->c_str () );
130 }
131 }
132
133 void
134 Project::SetConfigurationOption ( char* s,
135 string name )
136 {
137 SetConfigurationOption ( s, name, NULL );
138 }
139
140 void
141 Project::WriteConfigurationFile ()
142 {
143 char* buf;
144 char* s;
145
146 buf = (char*) malloc ( 10*1024 );
147 if ( buf == NULL )
148 throw OutOfMemoryException ();
149
150 s = buf;
151 s = s + sprintf ( s, "/* Automatically generated. " );
152 s = s + sprintf ( s, "Edit config.xml to change configuration */\n" );
153 s = s + sprintf ( s, "#ifndef __INCLUDE_CONFIG_H\n" );
154 s = s + sprintf ( s, "#define __INCLUDE_CONFIG_H\n" );
155
156 SetConfigurationOption ( s, "ARCH" );
157 SetConfigurationOption ( s, "OPTIMIZED" );
158 SetConfigurationOption ( s, "MP", new string ( "UP" ) );
159 SetConfigurationOption ( s, "ACPI" );
160 SetConfigurationOption ( s, "_3GB" );
161
162 s = s + sprintf ( s, "#endif /* __INCLUDE_CONFIG_H */\n" );
163
164 WriteIfChanged ( buf, "include" SSEP "roscfg.h" );
165
166 free ( buf );
167 }
168
169 void
170 Project::ExecuteInvocations ()
171 {
172 for ( size_t i = 0; i < modules.size (); i++ )
173 modules[i]->InvokeModule ();
174 }
175
176 void
177 Project::ReadXml ()
178 {
179 Path path;
180 head = XMLLoadFile ( xmlfile, path, xmlbuildfiles );
181 node = NULL;
182 for ( size_t i = 0; i < head->subElements.size (); i++ )
183 {
184 if ( head->subElements[i]->name == "project" )
185 {
186 node = head->subElements[i];
187 string path;
188 this->ProcessXML ( path );
189 return;
190 }
191 }
192
193 throw InvalidBuildFileException (
194 node->location,
195 "Document contains no 'project' tag." );
196 }
197
198 void
199 Project::ProcessXML ( const string& path )
200 {
201 const XMLAttribute *att;
202 if ( node->name != "project" )
203 throw Exception ( "internal tool error: Project::ProcessXML() called with non-<project> node" );
204
205 att = node->GetAttribute ( "name", false );
206 if ( !att )
207 name = "Unnamed";
208 else
209 name = att->value;
210
211 att = node->GetAttribute ( "makefile", true );
212 assert(att);
213 makefile = att->value;
214
215 size_t i;
216 for ( i = 0; i < node->subElements.size (); i++ )
217 ProcessXMLSubElement ( *node->subElements[i], path );
218 for ( i = 0; i < modules.size (); i++ )
219 modules[i]->ProcessXML ();
220 for ( i = 0; i < linkerFlags.size (); i++ )
221 linkerFlags[i]->ProcessXML ();
222 non_if_data.ProcessXML ();
223 for ( i = 0; i < cdfiles.size (); i++ )
224 cdfiles[i]->ProcessXML ();
225 for ( i = 0; i < installfiles.size (); i++ )
226 installfiles[i]->ProcessXML ();
227 }
228
229 void
230 Project::ProcessXMLSubElement ( const XMLElement& e,
231 const string& path,
232 If* pIf )
233 {
234 bool subs_invalid = false;
235 string subpath(path);
236 if ( e.name == "module" )
237 {
238 if ( pIf )
239 throw InvalidBuildFileException (
240 e.location,
241 "<module> is not a valid sub-element of <if>" );
242 Module* module = new Module ( *this, e, path );
243 if ( LocateModule ( module->name ) )
244 throw InvalidBuildFileException (
245 node->location,
246 "module name conflict: '%s' (originally defined at %s)",
247 module->name.c_str(),
248 module->node.location.c_str() );
249 modules.push_back ( module );
250 return; // defer processing until later
251 }
252 else if ( e.name == "cdfile" )
253 {
254 CDFile* cdfile = new CDFile ( *this, e, path );
255 cdfiles.push_back ( cdfile );
256 subs_invalid = true;
257 }
258 else if ( e.name == "installfile" )
259 {
260 InstallFile* installfile = new InstallFile ( *this, e, path );
261 installfiles.push_back ( installfile );
262 subs_invalid = true;
263 }
264 else if ( e.name == "directory" )
265 {
266 const XMLAttribute* att = e.GetAttribute ( "name", true );
267 assert(att);
268 subpath = GetSubPath ( e.location, path, att->value );
269 }
270 else if ( e.name == "include" )
271 {
272 Include* include = new Include ( *this, e );
273 if ( pIf )
274 pIf->data.includes.push_back ( include );
275 else
276 non_if_data.includes.push_back ( include );
277 subs_invalid = true;
278 }
279 else if ( e.name == "define" )
280 {
281 Define* define = new Define ( *this, e );
282 if ( pIf )
283 pIf->data.defines.push_back ( define );
284 else
285 non_if_data.defines.push_back ( define );
286 subs_invalid = true;
287 }
288 else if ( e.name == "linkerflag" )
289 {
290 linkerFlags.push_back ( new LinkerFlag ( *this, e ) );
291 subs_invalid = true;
292 }
293 else if ( e.name == "if" )
294 {
295 If* pOldIf = pIf;
296 pIf = new If ( e, *this, NULL );
297 if ( pOldIf )
298 pOldIf->data.ifs.push_back ( pIf );
299 else
300 non_if_data.ifs.push_back ( pIf );
301 subs_invalid = false;
302 }
303 else if ( e.name == "property" )
304 {
305 Property* property = new Property ( e, *this, NULL );
306 if ( pIf )
307 pIf->data.properties.push_back ( property );
308 else
309 non_if_data.properties.push_back ( property );
310 }
311 if ( subs_invalid && e.subElements.size() )
312 throw InvalidBuildFileException (
313 e.location,
314 "<%s> cannot have sub-elements",
315 e.name.c_str() );
316 for ( size_t i = 0; i < e.subElements.size (); i++ )
317 ProcessXMLSubElement ( *e.subElements[i], subpath, pIf );
318 }
319
320 Module*
321 Project::LocateModule ( const string& name )
322 {
323 for ( size_t i = 0; i < modules.size (); i++ )
324 {
325 if (modules[i]->name == name)
326 return modules[i];
327 }
328
329 return NULL;
330 }
331
332 const Module*
333 Project::LocateModule ( const string& name ) const
334 {
335 for ( size_t i = 0; i < modules.size (); i++ )
336 {
337 if ( modules[i]->name == name )
338 return modules[i];
339 }
340
341 return NULL;
342 }
343
344 std::string
345 Project::GetProjectFilename () const
346 {
347 return xmlfile;
348 }
349
350