mirror of https://gitlab.com/cppit/jucipp
20 changed files with 676 additions and 316 deletions
@ -0,0 +1,263 @@
|
||||
#include "cmake.h" |
||||
#include "sourcefile.h" |
||||
#include <regex> |
||||
#include "singletons.h" |
||||
|
||||
#include <iostream> //TODO: remove |
||||
using namespace std; //TODO: remove
|
||||
|
||||
CMake::CMake(const boost::filesystem::path &path) { |
||||
const auto find_cmake_project=[this](const boost::filesystem::path &cmake_path) { |
||||
for(auto &line: juci::filesystem::read_lines(cmake_path)) { |
||||
const std::regex project_regex("^ *project *\\(.*$"); |
||||
std::smatch sm; |
||||
if(std::regex_match(line, sm, project_regex)) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
}; |
||||
|
||||
auto search_path=boost::filesystem::path(path); |
||||
auto search_cmake_path=search_path; |
||||
search_cmake_path+="/CMakeLists.txt"; |
||||
if(boost::filesystem::exists(search_cmake_path)) |
||||
paths.emplace(paths.begin(), search_cmake_path); |
||||
if(find_cmake_project(search_cmake_path)) |
||||
project_path=search_path; |
||||
else { |
||||
do { |
||||
search_path=search_path.parent_path(); |
||||
search_cmake_path=search_path; |
||||
search_cmake_path+="/CMakeLists.txt"; |
||||
if(boost::filesystem::exists(search_cmake_path)) |
||||
paths.emplace(paths.begin(), search_cmake_path); |
||||
if(find_cmake_project(search_cmake_path)) { |
||||
project_path=search_path; |
||||
break; |
||||
} |
||||
} while(search_path!=search_path.root_directory()); |
||||
} |
||||
if(project_path!="") { |
||||
if(boost::filesystem::exists(project_path.string()+"/CMakeLists.txt") && !boost::filesystem::exists(project_path.string()+"/compile_commands.json")) |
||||
create_compile_commands(project_path.string()); |
||||
} |
||||
} |
||||
|
||||
bool CMake::create_compile_commands(const std::string &path) { |
||||
Singleton::terminal()->print("Creating "+boost::filesystem::path(path+"/compile_commands.json").string()+"\n"); |
||||
//TODO: Windows...
|
||||
if(Singleton::terminal()->execute("cmake . -DCMAKE_EXPORT_COMPILE_COMMANDS=ON 2>&1", path)==EXIT_SUCCESS) |
||||
return true; |
||||
return false; |
||||
} |
||||
|
||||
void CMake::read_files() { |
||||
for(auto &path: paths) |
||||
files.emplace_back(juci::filesystem::read(path)); |
||||
} |
||||
|
||||
void CMake::remove_tabs() { |
||||
for(auto &file: files) { |
||||
for(auto &chr: file) { |
||||
if(chr=='\t') |
||||
chr=' '; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void CMake::remove_comments() { |
||||
for(auto &file: files) { |
||||
size_t pos=0; |
||||
size_t comment_start; |
||||
bool inside_comment=false; |
||||
while(pos<file.size()) { |
||||
if(!inside_comment && file[pos]=='#') { |
||||
comment_start=pos; |
||||
inside_comment=true; |
||||
} |
||||
if(inside_comment && file[pos]=='\n') { |
||||
file.erase(comment_start, pos-comment_start); |
||||
pos-=pos-comment_start; |
||||
inside_comment=false; |
||||
} |
||||
pos++; |
||||
} |
||||
if(inside_comment) |
||||
file.erase(comment_start); |
||||
} |
||||
} |
||||
|
||||
void CMake::remove_newlines_inside_parentheses() { |
||||
for(auto &file: files) { |
||||
size_t pos=0; |
||||
bool inside_para=false; |
||||
bool inside_quote=false; |
||||
char last_char=0; |
||||
while(pos<file.size()) { |
||||
if(!inside_quote && file[pos]=='"' && last_char!='\\') |
||||
inside_quote=true; |
||||
else if(inside_quote && file[pos]=='"' && last_char!='\\') |
||||
inside_quote=false; |
||||
|
||||
else if(!inside_quote && file[pos]=='(') |
||||
inside_para=true; |
||||
else if(!inside_quote && file[pos]==')') |
||||
inside_para=false; |
||||
|
||||
else if(inside_para && file[pos]=='\n') |
||||
file.replace(pos, 1, 1, ' '); |
||||
last_char=file[pos]; |
||||
pos++; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void CMake::find_variables() { |
||||
for(auto &file: files) { |
||||
size_t pos=0; |
||||
while(pos<file.size()) { |
||||
auto start_line=pos; |
||||
auto end_line=file.find('\n', start_line); |
||||
if(end_line==std::string::npos) |
||||
end_line=file.size(); |
||||
if(end_line>start_line) { |
||||
auto line=file.substr(start_line, end_line-start_line); |
||||
const std::regex set_regex("^ *set *\\( *([A-Za-z_][A-Za-z_0-9]*) +(.*)\\) *$"); |
||||
std::smatch sm; |
||||
if(std::regex_match(line, sm, set_regex)) { |
||||
std::string data=sm[2]; |
||||
while(data.size()>0 && data.back()==' ') |
||||
data.pop_back(); |
||||
parse_variable_parameters(data); |
||||
variables[sm[1]]=data; |
||||
} |
||||
} |
||||
pos=end_line+1; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void CMake::parse_variable_parameters(std::string &data) { |
||||
size_t pos=0; |
||||
bool inside_quote=false; |
||||
char last_char=0; |
||||
while(pos<data.size()) { |
||||
if(!inside_quote && data[pos]=='"' && last_char!='\\') { |
||||
inside_quote=true; |
||||
data.erase(pos, 1); //TODO: instead remove quote-mark if pasted into a quote, for instance: "test${test}test"<-remove quotes from ${test}
|
||||
pos--; |
||||
} |
||||
else if(inside_quote && data[pos]=='"' && last_char!='\\') { |
||||
inside_quote=false; |
||||
data.erase(pos, 1); //TODO: instead remove quote-mark if pasted into a quote, for instance: "test${test}test"<-remove quotes from ${test}
|
||||
pos--; |
||||
} |
||||
else if(!inside_quote && data[pos]==' ' && pos+1<data.size() && data[pos+1]==' ') { |
||||
data.erase(pos, 1); |
||||
pos--; |
||||
} |
||||
|
||||
last_char=data[pos]; |
||||
pos++; |
||||
} |
||||
for(auto &var: variables) { |
||||
auto pos=data.find("${"+var.first+'}'); |
||||
while(pos!=std::string::npos) { |
||||
data.replace(pos, var.first.size()+3, var.second); |
||||
pos=data.find("${"+var.first+'}'); |
||||
} |
||||
} |
||||
|
||||
//Remove variables we do not know:
|
||||
pos=data.find("${"); |
||||
auto pos_end=data.find("}", pos+2); |
||||
while(pos!=std::string::npos && pos_end!=std::string::npos) { |
||||
data.erase(pos, pos_end-pos+1); |
||||
pos=data.find("${"); |
||||
pos_end=data.find("}", pos+2); |
||||
} |
||||
} |
||||
|
||||
void CMake::parse() { |
||||
read_files(); |
||||
remove_tabs(); |
||||
remove_comments(); |
||||
remove_newlines_inside_parentheses(); |
||||
find_variables(); |
||||
parsed=true; |
||||
} |
||||
|
||||
std::vector<std::string> CMake::get_function_parameters(std::string &data) { |
||||
std::vector<std::string> parameters; |
||||
size_t pos=0; |
||||
size_t parameter_pos=0; |
||||
bool inside_quote=false; |
||||
char last_char=0; |
||||
while(pos<data.size()) { |
||||
if(!inside_quote && data[pos]=='"' && last_char!='\\') { |
||||
inside_quote=true; |
||||
data.erase(pos, 1); |
||||
pos--; |
||||
} |
||||
else if(inside_quote && data[pos]=='"' && last_char!='\\') { |
||||
inside_quote=false; |
||||
data.erase(pos, 1); |
||||
pos--; |
||||
} |
||||
else if(!inside_quote && pos+1<data.size() && data[pos]==' ' && data[pos+1]==' ') { |
||||
data.erase(pos, 1); |
||||
pos--; |
||||
} |
||||
else if(!inside_quote && data[pos]==' ') { |
||||
parameters.emplace_back(data.substr(parameter_pos, pos-parameter_pos)); |
||||
if(pos+1<data.size()) |
||||
parameter_pos=pos+1; |
||||
} |
||||
|
||||
last_char=data[pos]; |
||||
pos++; |
||||
} |
||||
parameters.emplace_back(data.substr(parameter_pos)); |
||||
for(auto &var: variables) { |
||||
for(auto ¶meter: parameters) { |
||||
auto pos=parameter.find("${"+var.first+'}'); |
||||
while(pos!=std::string::npos) { |
||||
parameter.replace(pos, var.first.size()+3, var.second); |
||||
pos=parameter.find("${"+var.first+'}'); |
||||
} |
||||
} |
||||
} |
||||
return parameters; |
||||
} |
||||
|
||||
std::vector<std::pair<boost::filesystem::path, std::vector<std::string> > > CMake::get_functions_parameters(const std::string &name) { |
||||
if(!parsed) |
||||
parse(); |
||||
std::vector<std::pair<boost::filesystem::path, std::vector<std::string> > > functions; |
||||
size_t file_c=0; |
||||
for(auto &file: files) { |
||||
size_t pos=0; |
||||
while(pos<file.size()) { |
||||
auto start_line=pos; |
||||
auto end_line=file.find('\n', start_line); |
||||
if(end_line==std::string::npos) |
||||
end_line=file.size(); |
||||
if(end_line>start_line) { |
||||
auto line=file.substr(start_line, end_line-start_line); |
||||
const std::regex function_regex("^ *"+name+" *\\( *(.*)\\) *$"); |
||||
std::smatch sm; |
||||
if(std::regex_match(line, sm, function_regex)) { |
||||
std::string data=sm[1]; |
||||
while(data.size()>0 && data.back()==' ') |
||||
data.pop_back(); |
||||
auto parameters=get_function_parameters(data); |
||||
functions.emplace(functions.begin(), paths[file_c], parameters); |
||||
} |
||||
} |
||||
pos=end_line+1; |
||||
} |
||||
file_c++; |
||||
} |
||||
return functions; |
||||
} |
||||
@ -0,0 +1,28 @@
|
||||
#ifndef JUCI_CMAKE_H_ |
||||
#define JUCI_CMAKE_H_ |
||||
#include <boost/filesystem.hpp> |
||||
#include <vector> |
||||
#include <unordered_map> |
||||
|
||||
class CMake { |
||||
public: |
||||
CMake(const boost::filesystem::path &path); |
||||
std::vector<std::pair<boost::filesystem::path, std::vector<std::string> > > get_functions_parameters(const std::string &name); |
||||
static bool create_compile_commands(const std::string &path); |
||||
|
||||
std::vector<boost::filesystem::path> paths; |
||||
std::vector<std::string> files; |
||||
boost::filesystem::path project_path; |
||||
std::unordered_map<std::string, std::string> variables; |
||||
private: |
||||
void read_files(); |
||||
void remove_tabs(); |
||||
void remove_comments(); |
||||
void remove_newlines_inside_parentheses(); |
||||
void find_variables(); |
||||
void parse_variable_parameters(std::string &data); |
||||
void parse(); |
||||
std::vector<std::string> get_function_parameters(std::string &data); |
||||
bool parsed=false; |
||||
}; |
||||
#endif //JUCI_CMAKE_H_
|
||||
Loading…
Reference in new issue