Quick and dirty. Ignores files without a period so that standard headers are ignored. Also assumes all files are in the current directory (doesn't implement include path lookup stuff). If you actually want to use it I'll probably put a path lookup in there (or feel free to do it yourself :-P).
Code:
#include <cassert>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <list>
#include <string>
void ShowIncludes(const std::string& filename, std::list<std::string>& includes);
int main(int argc, char** argv)
{
if (argc != 2)
{
std::cerr << "Usage: " << argv[0] << " filename" << std::endl;
return 0;
}
std::list<std::string> includes;
ShowIncludes(argv[1], includes);
includes.sort();
for (std::list<std::string>::iterator it = includes.begin(); it != includes.end(); ++it)
std::cout << *it << std::endl;
return 0;
}
void ShowIncludes(const std::string& filename, std::list<std::string>& includes)
{
std::ifstream ifs(filename.c_str());
if (!ifs.good())
{
std::cerr << "Couldn't open " << filename << std::endl;
exit(1);
}
std::string line;
getline(ifs, line);
while (!ifs.eof())
{
if (line.size() >= 12 && line[0] == '#')
{
int start = 1;
while (start < line.size() && line[start] == ' ')
++start;
bool couldBeInclude = true;
for (int i = 0; i != 7 && couldBeInclude; ++i)
couldBeInclude &= (line[start + i] == "include"[i]);
if (couldBeInclude)
{
int fileStart = start + 7;
while (fileStart < line.size() && line[fileStart] == ' ')
++fileStart;
assert(fileStart < line.size());
assert(line[fileStart] == '"' || line[fileStart] == '<');
++fileStart;
int fileEnd = fileStart;
bool dotFound = false;
while (fileEnd < line.size() && line[fileEnd] != '"' && line[fileEnd] != '>')
{
dotFound |= (line[fileEnd] == '.');
++fileEnd;
}
assert(fileEnd < line.size());
assert(line[fileEnd] == '"' || line[fileEnd] == '>');
if (dotFound) // ignore standard headers that don't have a period in them
{
line[fileEnd] = '\0';
includes.push_back(&line[fileStart]);
ShowIncludes(includes.back(), includes);
}
}
}
getline(ifs, line);
}
}
I just realised you can take advantage of the preprocessor for this and if you're on linux you can also use grep and such to do this quite easily:
Code:
g++ -E $1 |\
grep '^# [0-9]* "[^"]*"' |\
grep -o '"[^"]*"' |\
grep -o '[^"<>]*' |\
grep -v '^/usr/' |\
sort |\
uniq