6 /* Read at most this amount of bytes from each file and assume that all #includes are located within this block */
7 #define MAX_BYTES_TO_READ 4096
13 SourceFile::SourceFile ( AutomaticDependency
* automaticDependency
,
15 const string
& filename
,
17 bool isNonAutomaticDependency
)
18 : automaticDependency ( automaticDependency
),
20 filename ( filename
),
21 isNonAutomaticDependency ( isNonAutomaticDependency
),
22 youngestLastWriteTime ( 0 )
25 parents
.push_back ( parent
);
26 GetDirectoryAndFilenameParts ();
30 SourceFile::GetDirectoryAndFilenameParts ()
32 size_t index
= filename
.find_last_of ( CSEP
);
33 if ( index
!= string::npos
)
35 directoryPart
= filename
.substr ( 0, index
);
36 filenamePart
= filename
.substr ( index
+ 1, filename
.length () - index
);
41 filenamePart
= filename
;
58 FILE* f
= fopen ( filename
.c_str (), "rb" );
60 throw FileNotFoundException ( filename
);
62 if ( fstat ( fileno ( f
), &statbuf
) != 0 )
65 throw AccessDeniedException ( filename
);
67 lastWriteTime
= statbuf
.st_mtime
;
69 unsigned long len
= (unsigned long) filelen ( f
);
70 if ( len
> MAX_BYTES_TO_READ
)
71 len
= MAX_BYTES_TO_READ
;
73 fread ( &buf
[0], 1, len
, f
);
80 SourceFile::SkipWhitespace ()
82 while ( p
< end
&& isspace ( *p
))
87 SourceFile::ReadInclude ( string
& filename
,
92 if ( ( *p
== '#') && ( end
- p
> 13 ) )
99 if ( strncmp ( p
, "include ", 8 ) == 0 )
105 if ( strncmp ( p
, "include_next ", 13 ) == 0 )
117 register char ch
= *p
;
118 if ( ch
== '<' || ch
== '"' )
121 filename
.resize ( MAX_PATH
);
124 while ( p
< end
&& ch
!= '>' && ch
!= '"' && ch
!= '\n' )
131 filename
.resize ( i
);
146 SourceFile::IsParentOf ( const SourceFile
* parent
,
147 const SourceFile
* child
)
150 for ( i
= 0; i
< child
->parents
.size (); i
++ )
152 if ( child
->parents
[i
] != NULL
)
154 if ( child
->parents
[i
] == parent
)
158 for ( i
= 0; i
< child
->parents
.size (); i
++ )
160 if ( child
->parents
[i
] != NULL
)
162 if ( IsParentOf ( parent
,
163 child
->parents
[i
] ) )
171 SourceFile::IsIncludedFrom ( const string
& normalizedFilename
)
173 if ( normalizedFilename
== filename
)
176 SourceFile
* sourceFile
= automaticDependency
->RetrieveFromCache ( normalizedFilename
);
177 if ( sourceFile
== NULL
)
180 return IsParentOf ( sourceFile
,
185 SourceFile::GetParentSourceFile ()
187 if ( isNonAutomaticDependency
)
193 SourceFile::CanProcessFile ( const string
& extension
)
195 if ( extension
== ".h" || extension
== ".H" )
197 if ( extension
== ".c" || extension
== ".C" )
199 if ( extension
== ".cpp" || extension
== ".CPP" )
201 if ( extension
== ".rc" || extension
== ".RC" )
203 if ( extension
== ".s" || extension
== ".S" )
209 SourceFile::ParseFile ( const string
& normalizedFilename
)
211 string extension
= GetExtension ( normalizedFilename
);
212 if ( CanProcessFile ( extension
) )
214 if ( IsIncludedFrom ( normalizedFilename
) )
217 SourceFile
* sourceFile
= automaticDependency
->RetrieveFromCacheOrParse ( module
,
219 GetParentSourceFile () );
231 string
includedFilename ( "" );
234 while ( ReadInclude ( includedFilename
,
237 string
resolvedFilename ( "" );
238 bool locatedFile
= automaticDependency
->LocateIncludedFile ( this,
245 SourceFile
* sourceFile
= ParseFile ( resolvedFilename
);
246 if ( sourceFile
!= NULL
)
247 files
.push_back ( sourceFile
);
256 SourceFile::Location () const
259 const char* end_of_line
= strchr ( buf
.c_str (), '\n' );
260 while ( end_of_line
&& end_of_line
< p
)
263 end_of_line
= strchr ( end_of_line
+ 1, '\n' );
265 return ssprintf ( "%s(%i)",
271 AutomaticDependency::AutomaticDependency ( const Project
& project
)
272 : project ( project
)
276 AutomaticDependency::~AutomaticDependency ()
278 std::map
<std::string
, SourceFile
*>::iterator theIterator
;
279 for ( theIterator
= sourcefile_map
.begin (); theIterator
!= sourcefile_map
.end (); theIterator
++ )
280 delete theIterator
->second
;
284 AutomaticDependency::Process ()
286 for ( size_t i
= 0; i
< project
.modules
.size (); i
++ )
287 ProcessModule ( *project
.modules
[i
] );
291 AutomaticDependency::GetModuleFiles ( Module
& module
,
292 vector
<File
*>& files
) const
294 for ( size_t i
= 0; i
< module
.non_if_data
.files
.size (); i
++ )
295 files
.push_back ( module
.non_if_data
.files
[i
] );
297 /* FIXME: Collect files in IFs here */
299 if ( module
.pch
!= NULL
)
300 files
.push_back ( &module
.pch
->file
);
304 AutomaticDependency::ProcessModule ( Module
& module
)
307 GetModuleFiles ( module
, files
);
308 for ( size_t i
= 0; i
< files
.size (); i
++ )
309 ProcessFile ( module
, *files
[i
] );
313 AutomaticDependency::ProcessFile ( Module
& module
,
316 string normalizedFilename
= NormalizeFilename ( file
.name
);
317 RetrieveFromCacheOrParse ( module
,
323 AutomaticDependency::LocateIncludedFile ( const string
& directory
,
324 const string
& includedFilename
,
325 string
& resolvedFilename
)
327 string normalizedFilename
= NormalizeFilename ( directory
+ SSEP
+ includedFilename
);
328 FILE* f
= fopen ( normalizedFilename
.c_str (), "rb" );
332 resolvedFilename
= normalizedFilename
;
335 resolvedFilename
= "";
340 AutomaticDependency::GetFilename ( const string
& filename
)
342 size_t index
= filename
.find_last_of ( CSEP
);
343 if (index
== string::npos
)
346 return filename
.substr ( index
+ 1,
347 filename
.length () - index
- 1);
351 AutomaticDependency::LocateIncludedFile ( SourceFile
* sourceFile
,
353 const string
& includedFilename
,
355 string
& resolvedFilename
)
358 const vector
<Include
*>* pincludes
;
359 for ( i
= 0; i
< 2; i
++ )
362 pincludes
= &module
.non_if_data
.includes
;
364 pincludes
= &module
.project
.non_if_data
.includes
;
365 const vector
<Include
*>& includes
= *pincludes
;
366 for ( j
= 0; j
< includes
.size (); j
++ )
368 Include
& include
= *includes
[j
];
369 if ( LocateIncludedFile ( include
.directory
,
373 if ( includeNext
&& stricmp ( resolvedFilename
.c_str (),
374 sourceFile
->filename
.c_str () ) == 0 )
381 resolvedFilename
= "";
386 AutomaticDependency::RetrieveFromCacheOrParse ( Module
& module
,
387 const string
& filename
,
388 SourceFile
* parentSourceFile
)
390 SourceFile
* sourceFile
= sourcefile_map
[filename
];
391 if ( sourceFile
== NULL
)
393 sourceFile
= new SourceFile ( this,
398 sourcefile_map
[filename
] = sourceFile
;
399 sourceFile
->Parse ();
401 else if ( parentSourceFile
!= NULL
)
402 sourceFile
->parents
.push_back ( parentSourceFile
);
407 AutomaticDependency::RetrieveFromCache ( const string
& filename
)
409 return sourcefile_map
[filename
];
413 AutomaticDependency::CheckAutomaticDependencies ( bool verbose
)
415 struct utimbuf timebuf
;
416 for ( size_t mi
= 0; mi
< project
.modules
.size (); mi
++ )
419 GetModuleFiles ( *project
.modules
[mi
], files
);
420 for ( size_t fi
= 0; fi
< files
.size (); fi
++ )
422 File
& file
= *files
[fi
];
423 string normalizedFilename
= NormalizeFilename ( file
.name
);
425 SourceFile
* sourceFile
= RetrieveFromCache ( normalizedFilename
);
426 if ( sourceFile
!= NULL
)
428 CheckAutomaticDependenciesForFile ( sourceFile
);
429 assert ( sourceFile
->youngestLastWriteTime
!= 0 );
430 if ( sourceFile
->youngestLastWriteTime
> sourceFile
->lastWriteTime
)
434 printf ( "Marking %s for rebuild due to younger file %s\n",
435 sourceFile
->filename
.c_str (),
436 sourceFile
->youngestFile
->filename
.c_str () );
438 timebuf
.actime
= sourceFile
->youngestLastWriteTime
;
439 timebuf
.modtime
= sourceFile
->youngestLastWriteTime
;
440 utime ( sourceFile
->filename
.c_str (),
449 AutomaticDependency::CheckAutomaticDependenciesForFile ( SourceFile
* sourceFile
)
451 if ( sourceFile
->youngestLastWriteTime
> 0 )
454 if ( sourceFile
->files
.size () == 0 )
456 sourceFile
->youngestLastWriteTime
= sourceFile
->lastWriteTime
;
457 sourceFile
->youngestFile
= sourceFile
;
461 for ( size_t i
= 0; i
< sourceFile
->files
.size (); i
++ )
463 SourceFile
* childSourceFile
= sourceFile
->files
[i
];
465 CheckAutomaticDependenciesForFile ( childSourceFile
);
466 if ( ( childSourceFile
->youngestLastWriteTime
> sourceFile
->youngestLastWriteTime
) ||
467 ( childSourceFile
->lastWriteTime
> sourceFile
->youngestLastWriteTime
) )
469 if ( childSourceFile
->youngestLastWriteTime
> childSourceFile
->lastWriteTime
)
471 sourceFile
->youngestLastWriteTime
= childSourceFile
->youngestLastWriteTime
;
472 sourceFile
->youngestFile
= childSourceFile
->youngestFile
;
476 sourceFile
->youngestLastWriteTime
= childSourceFile
->lastWriteTime
;
477 sourceFile
->youngestFile
= childSourceFile
;