有时候我们想阅读开源的代码,在windows下vs是最好的IDE,但是开源代码不提供vs的工程文件,新建工程简单但是上百个文件的添加就比较傻逼了。下面提供一段代码爬目录修改vcproj 的xml描述文件,有需求可以参考下,丰富下功能:
#include <iostream>
#include <list>
#include <map>
#include <io.h>
#include <windows.h>
#include <algorithm>
#include <string>
#include <cstring>
#include <sys/stat.h>
#include "tinyxml2.h"
using namespace std;
using namespace tinyxml2;
class fileNode
{
public:
fileNode(){
fileList.clear();
dirList.clear();
}
public:
list<string> fileList;
map<string, fileNode> dirList;
};
void getFileList(const string& sPath,fileNode& rNode);
void getFile(const string& sPath,fileNode& rNode,_finddata_t& file)
{
string filename = file.name;
if(filename == "." || filename == "..")
{
return ;
}
string sAddPath = sPath;
sAddPath += filename;
struct stat st;
stat(sAddPath.c_str(), &st);
if(st.st_mode & S_IFDIR == S_IFDIR)
{
sAddPath += "\\";
getFileList(sAddPath, rNode.dirList[filename]);
}
else
{
rNode.fileList.push_back(sAddPath);
}
}
void getFileList(const string& sPath,fileNode& rNode)
{
struct _finddata_t file;
long hFile;
string sPathLast = sPath + "*"; // sPathLast = "c:\test\*.*"
hFile = _findfirst(sPathLast.c_str(), &file);
if(hFile == -1)
{
return;
}
else
{
getFile(sPath,rNode,file);
}
while(_findnext(hFile, &file) != -1)
{
getFile(sPath,rNode,file);
}
}
void xmlEleFileList(XMLElement* elemXml, map<string, bool>& fileMap)
{
fileMap.clear();
if(elemXml == NULL)
{
return;
}
XMLElement* pNode = elemXml->FirstChildElement("File");
while(pNode != NULL)
{
const char* pName = pNode->Attribute("RelativePath");
if(pName != NULL)
{
fileMap[pName] = false;
}
pNode = pNode->NextSiblingElement("File");
}
}
void xmlEleAddFile(XMLElement* elemXml, const string& fileName)
{
if(elemXml == NULL)
return;
tinyxml2::XMLDocument* doc = elemXml->GetDocument();
XMLElement* pNode = doc->NewElement("File");
pNode->SetAttribute( "RelativePath", fileName.c_str());
elemXml->InsertEndChild(pNode);
}
void xmlEleRemoveFile(XMLElement* elemXml, map<string, bool>& fileMap)
{
if(elemXml == NULL)
{
return;
}
XMLElement* pNode = elemXml->FirstChildElement("File");
while(pNode != NULL)
{
string rName = pNode->Attribute("RelativePath");
if(rName.length() > 0 && fileMap.find(rName) != fileMap.end() && fileMap[rName] == false)
{
XMLElement* pOld = pNode;
pNode = pOld->NextSiblingElement("File");
elemXml->DeleteChild(pOld);
continue;
}
pNode = pNode->NextSiblingElement("File");
}
}
void saveFileList(fileNode& rNode, XMLElement* elemXml);
void xmlEleCheckDir(XMLElement* elemXml,const string& dirName, fileNode& rNode)
{
if(elemXml == NULL)
return;
bool bfind = false;
XMLElement* pNode = elemXml->FirstChildElement("Filter");
while(pNode != NULL)
{
string rName = pNode->Attribute("Name");
if(rName == dirName)
{
bfind = true;
break;
}
pNode = pNode->NextSiblingElement("Filter");
}
if(bfind == false)
{
pNode = NULL;
}
bool binsert = false;
if(pNode == NULL)
{
tinyxml2::XMLDocument* doc = elemXml->GetDocument();
pNode = doc->NewElement("Filter");
pNode->SetAttribute( "Name", dirName.c_str());
binsert = true;
}
saveFileList(rNode, pNode);
if(binsert == true)
{
elemXml->InsertEndChild(pNode);
}
}
void xmlEleRemoveDir(XMLElement* elemXml, map<string, bool>& dirMap)
{
if(elemXml == NULL)
{
return;
}
XMLElement* pNode = elemXml->FirstChildElement("Filter");
while(pNode != NULL)
{
string rName = pNode->Attribute("Name");
if(rName.length() > 0 && dirMap.find(rName) == dirMap.end())
{
XMLElement* pOld = pNode;
pNode = pOld->NextSiblingElement("Filter");
elemXml->DeleteChild(pOld);
continue;
}
pNode = pNode->NextSiblingElement("Filter");
}
}
void saveFileList(fileNode& rNode, XMLElement* elemXml)
{
if(elemXml == NULL)
return;
map<string, bool> fileMap;
xmlEleFileList(elemXml, fileMap);
for(list<string>::iterator iter = rNode.fileList.begin(); iter != rNode.fileList.end(); iter++)
{
string& filename = *iter;
if(fileMap.find(filename) == fileMap.end())
{
xmlEleAddFile(elemXml, filename);
}
fileMap[filename] = true;
}
xmlEleRemoveFile(elemXml, fileMap);
fileMap.clear();
for(map<string, fileNode>::iterator iter = rNode.dirList.begin(); iter != rNode.dirList.end(); iter ++)
{
xmlEleCheckDir(elemXml, iter->first, iter->second);
//fileMap[iter->first] = true;
}
//xmlEleRemoveDir(elemXml, fileMap);
//fileMap.clear();
}
int main(int argc,char** argv)
{
if(argc > 2)
{
string xmlfile(argv[1]);
string filedir(argv[2]);
//获得列表
fileNode root;
getFileList(filedir,root);
tinyxml2::XMLDocument doc;
if(doc.LoadFile(xmlfile.c_str()) != 0)
{
cout<<"读取文件:"<<xmlfile<<"失败!"<<endl;
return -1;
}
XMLElement* elemProj = doc.FirstChildElement("VisualStudioProject");
if(elemProj == NULL)
{
cout<<"读取文件:"<<xmlfile<<"失败,VisualStudioProject节点不存在!"<<endl;
return -2;
}
bool badd = false;
XMLElement* elemFiles = elemProj->FirstChildElement("Files");
if(elemFiles == NULL)
{
elemFiles = doc.NewElement("Files");
badd = true;
}
saveFileList(root, elemFiles);
if(badd == true)
{
elemProj->InsertEndChild(elemFiles);
}
doc.SaveFile(xmlfile.c_str());
}
else
{
cout<<"usetage: addvsdir 工程文件 相对目录"<<endl;
}
return 0;
}