//使用的格式:  ./checkMemory 被测试文件名 --
int main(int argc,const char **argv) {

	//----此块基本一样    start----
    struct stat sb;             

    //set compilerinstance for rewriter		
	std::string fileName(argv[1]);
	if (stat(fileName.c_str(), &sb) == -1){
        perror(fileName.c_str());
        exit(EXIT_FAILURE);
    }

	
	CompilerInstance compiler;
	DiagnosticOptions diagnosticOptions;
	compiler.createDiagnostics();


	//invocation可以传递任何flag给preprocessor
	CompilerInvocation *Invocation = new CompilerInvocation;

	CompilerInvocation::CreateFromArgs(*Invocation, argv + 1, argv + argc-1,compiler.getDiagnostics());

	compiler.setInvocation(Invocation);


	//建立TargetOptions和TargetInfo,并设置好Target
	// Set default target triple
	llvm::IntrusiveRefCntPtr<TargetOptions> pto( new TargetOptions());
	pto->Triple = llvm::sys::getDefaultTargetTriple();
	llvm::IntrusiveRefCntPtr<TargetInfo>
	 pti(TargetInfo::CreateTargetInfo(compiler.getDiagnostics(),
		                              pto.getPtr()));
	compiler.setTarget(pti.getPtr());

	//FileManager,SourceManager 以及heaDREearch的Options的设置
	compiler.createFileManager();
	compiler.createSourceManager(compiler.getFileManager());

	HeaderSearchOptions &headerSearchOptions = compiler.getHeaderSearchOpts();
	headerSearchOptions.AddPath("/usr/include/c++",
		  clang::frontend::Angled,
		  false,
		  false);
	
    headerSearchOptions.AddPath("/usr/local/lib/clang/3.5.0/include",
          clang::frontend::Angled,
          false,
          false);
    headerSearchOptions.AddPath("/usr/include/i386-linux-gnu",
          clang::frontend::Angled,
          false,
          false);
    headerSearchOptions.AddPath("/usr/include",
          clang::frontend::Angled,
          false,
          false);
	
    
    
/*
    headerSearchOptions.AddPath("/usr/include",
          clang::frontend::Angled,
          false,
          false);
	*/
	//langOptions设置,要传给rewriter
   	LangOptions langOpts;
	langOpts.GNUMode = 1; 
	langOpts.CXXExceptions = 1; 
	langOpts.RTTI = 1; 
	langOpts.Bool = 1; 
	langOpts.CPlusPlus = 1; 
	Invocation->setLangDefaults(langOpts, clang::IK_CXX,clang::LangStandard::lang_cxx0x);

	//create PP
	compiler.createPreprocessor();//(TU_Complete);//
	compiler.getPreprocessorOpts().UsePredefines = false;
	//createASTContext
	compiler.createASTContext();
  
 	//set the sourceManager for rewriter 

	
	rewrite.setSourceMgr(compiler.getSourceManager(), compiler.getLangOpts());
	
	//插装文件入口

	const FileEntry *pFile = compiler.getFileManager().getFile(fileName);
	compiler.getSourceManager().createMainFileID(pFile);
	compiler.getDiagnosticClient().BeginSourceFile(compiler.getLangOpts(),&compiler.getPreprocessor());
	                                        
	
	MyASTConsumer astConsumer(rewrite);
	//将.c转成_out.c
	// Convert <file>.c to <file_out>.c
	std::string outName (fileName);
	/*size_t ext = outName.rfind(".");
	//根据有没有找到‘。’来决定在哪里加入_out
	if (ext == std::string::npos)
		ext = outName.length();
	outName.insert(ext, "_out");
	*/
	outName.insert(outName.length(),"_out");
	llvm::errs() << "Output to: " << outName << "\n";
	
	std::string OutErrorInfo;
	//新建输入到新文件的流
	llvm::raw_fd_ostream outFile(outName.c_str(), OutErrorInfo);//,llvm::sys::fs::F_None);//版本问题//////


	//----此块基本一样    end----

	if (OutErrorInfo.empty()){
		// Parse the AST
		//用PP,astConsumer,ASTContext来解释AST
		ParseAST(compiler.getPreprocessor(), &astConsumer, compiler.getASTContext());
		compiler.getDiagnosticClient().EndSourceFile();
    
		//建立ClangTool 
        CommonOptionsParser OptionsParser(argc, argv);//, MyToolCategory);
        ClangTool Tool(OptionsParser.getCompilations(),
                 OptionsParser.getSourcePathList());
		//开始匹配             
        
        MallocVarPrinter mallocVarPrinter;
        MatchFinder mallocVarFinder;
        mallocVarFinder.addMatcher(MallocVarMatcher, &mallocVarPrinter);
        Tool.run(newFrontendActionFactory(&mallocVarFinder));
        
        MallocPrinter mallocPrinter;
        MatchFinder mallocFinder;
        mallocFinder.addMatcher(MallocMatcher, &mallocPrinter);
        Tool.run(newFrontendActionFactory(&mallocFinder));
        
        FreeVarPrinter freeVarPrinter;
        MatchFinder freeVarFinder;
        freeVarFinder.addMatcher(FreeVarMatcher, &freeVarPrinter);
        Tool.run(newFrontendActionFactory(&freeVarFinder));
        
        FreePrinter freePrinter;
        MatchFinder freeFinder;
        freeFinder.addMatcher(FreeMatcher, &freePrinter);
        Tool.run(newFrontendActionFactory(&freeFinder));
   
    
                  
    	const RewriteBuffer *RewriteBuf =rewrite.getRewriteBufferFor(compiler.getSourceManager().getMainFileID());
		
        if(RewriteBuf != NULL){
            #ifdef DEBUG
            llvm::errs() << " RewriteBuf not NULL \n";
			//在文件头加上改头文件,防止没有 stdlib,stdio 而不能使用printf和exit函数
		    #endif
			outFile << "#include\"plugHead.h\"\n";
            
            outFile << std::string(RewriteBuf->begin(), RewriteBuf->end());		
        }else{
            #ifdef DEBUG
            llvm::errs() << " RewriteBuf is NULL \n";
			#endif

        	outFile << "#include\"plugHead.h\"\n";
            std::ifstream infile(fileName.c_str());
            if(!infile){
                llvm::errs() << " fail to open the input file!\n";
                exit(-1);                
            }
            std::string str_in;
            while(std::getline(infile,str_in)){
                outFile << str_in <<"\n";
            }
        
        }
        outFile.close();


        #ifdef DEBUG        
        std::string checkStructErrorInfo;
        std::string checkStructFileName = "checkStruct.txt";
        //新建输入到新文件的流,将已经找到的malloc过的结构体信息写入文件,供另一个处理程序读取
        llvm::raw_fd_ostream csFile(checkStructFileName.c_str(),checkStructErrorInfo);//,llvm::sys::fs::F_None);
        if (checkStructErrorInfo.empty()){
      	    for(unsigned int i=0;i<cpVec.size();++i){            
    	        csFile << cpVec[i].name << " " << cpVec[i].row << " " << cpVec[i].col << " " << cpVec[i].declName << " " << cpVec[i].declRow << " " << cpVec[i].declCol << "\n" ;
	        }            
        }
	    csFile.close();  
        for(unsigned int i=0;i<cpVec.size();++i){
	        llvm::errs()<<cpVec[i].name<<"|"<<cpVec[i].declName<<":"<<cpVec[i].declRow<<":"<<cpVec[i].declCol<<"\n";  
	    }	
        #endif
	    
	}
	else{
		llvm::errs() << "Cannot open " << outName << " for writing\n";
	}
	

      
    return 0;
}