Listing 2
#include <iostream>
#include <string>
#include <boost/lexical_cast.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/exception.hpp>
#include <boost/graph/graphviz.hpp>
namespace bfs = boost::filesystem;
typedef boost::GraphvizDigraph Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor VertexDescriptor;
bool TraversePath(bfs::path topDir, VertexDescriptor topDirVertex,
unsigned int depth, Graph& treeGraph);
VertexDescriptor CreateVertex(std::string dirName, Graph& treeGraph);
int main(int argc, char* argv[])
{
// Parse command line arguments
if (argc != 3) {
std::cerr << "Usage: dirtree <topDir> <depth>" << std::endl;
return -1;
}
bfs::path topDir(argv[1]);
if (!is_directory(topDir)) {
std::cerr << "Usage: dirtree <topDir> <depth>" << std::endl;
return -1;
}
unsigned int depth;
try {
depth = boost::lexical_cast<unsigned int>(argv[2]);
}
catch (boost::bad_lexical_cast&) {
std::cerr << "Usage: dirtree <topDir> <depth>" << std::endl;
return -1;
}
// Construct the graph
Graph treeGraph;
VertexDescriptor topDirVertex =
CreateVertex(topDir.native_directory_string(), treeGraph);
TraversePath(topDir, topDirVertex, depth, treeGraph);
// Set properties of the graph
boost::graph_property<Graph, boost::graph_graph_attribute_t>::
type& graphAttr = boost::get_property(treeGraph,
boost::graph_graph_attribute);
graphAttr["name"] = "treeDir";
graphAttr["rankdir"] = "LR";
// Set properties that apply to all the nodes of the graph
boost::graph_property<Graph, boost::graph_vertex_attribute_t>::
type& graphVertAttr = boost::get_property(treeGraph,
boost::graph_vertex_attribute);
graphVertAttr["shape"] = "box";
graphVertAttr["height"] = "0.1";
// Output the graph
boost::write_graphviz("1.dot", treeGraph);
std::cout << num_vertices(treeGraph) << std::endl;
}
bool TraversePath(bfs::path topPath, VertexDescriptor topDirVertex,
unsigned int depth, Graph& treeGraph)
{
// Safety checks
if (!bfs::exists(topPath)) {
return false;
}
bfs::directory_iterator dirIter, endIter;
try {
dirIter = bfs::directory_iterator(topPath);
}
catch (bfs::filesystem_error& err) {
// We cannot traverse this directory, mark it with a dashed line
std::cerr << "Error: " << err.what() << std::endl;
const boost::property_map<Graph, boost::vertex_attribute_t>::
type& vertAttr = boost::get(boost::vertex_attribute, treeGraph);
vertAttr[topDirVertex]["style"] = "dashed";
return false;
}
try {
for ( ; dirIter != endIter; ++dirIter) {
// Process only directories under topPath (discard files)
if (is_directory(*dirIter)) {
VertexDescriptor newVertex =
CreateVertex(dirIter->leaf(), treeGraph);
add_edge(topDirVertex, newVertex, treeGraph);
if (depth > 1) {
// Recursion through the subdirectory
TraversePath(*dirIter, newVertex, depth-1, treeGraph);
}
}
}
}
catch (bfs::filesystem_error& err) {
std::cerr << "Error: " << err.what() << std::endl;
return false;
}
return true;
}
VertexDescriptor CreateVertex(std::string dirName, Graph& treeGraph)
{
// Add the vertex
VertexDescriptor vertex = add_vertex(treeGraph);
// Add its property
const boost::property_map<Graph, boost::vertex_attribute_t>::
type& vertAttrMap = boost::get(boost::vertex_attribute, treeGraph);
vertAttrMap[vertex]["label"] = dirName;
return vertex;
}