/*
* The ManaPlus Client
* Copyright (C) 2014 The ManaPlus Developers
*
* This file is part of The ManaPlus Client.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "lintmanager.h"
#include "rulebase.h"
#include "stringutils.h"
#include <dirent.h>
#include <fstream>
#include <regex>
#include <sys/stat.h>
#include "localconsts.h"
LintManager lint;
LintManager::LintManager() :
mFileName(),
mRootPath()
{
}
void LintManager::run(std::string path)
{
mRootPath = path;
size_t idx = path.rfind("src/");
if (idx != std::string::npos)
mRootPath = mRootPath.substr(0, idx);
if (!strEndWith(mRootPath, "/"))
mRootPath.append("/");
updateRules();
enumFiles(path);
}
void LintManager::updateRules()
{
FOR_EACH (std::vector<RuleBase*>::iterator, it, mRules)
(*it)->setRootDir(mRootPath);
}
void LintManager::addRule(RuleBase *const rule)
{
mRules.push_back(rule);
}
void LintManager::deleteRule(RuleBase *const rule)
{
deleteFrom(rule, mRules);
}
void LintManager::deleteSelectedRule(RuleBase *const rule)
{
deleteFrom(rule, mSelectedRules);
}
void LintManager::deleteFrom(RuleBase *const rule,
std::vector<RuleBase*> &rules)
{
FOR_EACH (std::vector<RuleBase*>::iterator, it, rules)
{
if (*it == rule)
{
rules.erase(it);
return;
}
}
}
void LintManager::enumFiles(std::string path)
{
path += "/";
struct dirent *next_file = nullptr;
DIR *const dir = opendir(path.c_str());
struct stat s;
std::vector<std::string> dirs;
while ((next_file = readdir(dir)))
{
const std::string file = next_file->d_name;
if (file != "." && file != "..")
{
const std::string name = path + file;
stat(name.c_str(), &s);
if (S_ISDIR(s.st_mode))
dirs.push_back(name);
else
processFile(name);
}
}
if (dir)
closedir(dir);
FOR_EACH (std::vector<std::string>::const_iterator, it, dirs)
enumFiles(*it);
}
void LintManager::processFile(std::string fileName)
{
// printf("file: %s\n", fileName.c_str());
mFileName = fileName;
selectRulesForFile();
if (!mSelectedRules.empty())
{
readFile();
applyRulesToFile();
}
}
void LintManager::applyRulesToFile()
{
FOR_EACH (std::vector<RuleBase*>::iterator, it, mSelectedRules)
{
RuleBase *const rule = *it;
int line = 1;
FOR_EACH (std::vector<std::string>::const_iterator, itStr, mFileData)
{
const std::string &str = *itStr;
rule->setLine(line);
rule->parseLine(str);
if (!rule->getFlag())
break;
line ++;
}
if (rule->getFlag())
rule->end();
}
}
void LintManager::readFile()
{
// printf("readFile: %s\n", mFileName.c_str());
std::ifstream file;
char line[3001];
mFileData.clear();
file.open(mFileName.c_str(), std::ios::in);
if (!file.is_open())
return;
while (file.getline(line, 3000))
mFileData.push_back(line);
if (file.is_open())
file.close();
}
void LintManager::selectRulesForFile()
{
// printf("selectRulesForFile: %s\n", mFileName.c_str());
mSelectedRules.clear();
FOR_EACH (std::vector<RuleBase*>::iterator, it, mRules)
{
RuleBase *const rule = *it;
if (isMatchFile(rule))
{
// printf("set file %s, for rule %s\n",
// mFileName.c_str(), rule->getName().c_str());
rule->init();
rule->setFile(mFileName);
rule->start();
if (rule->getFlag())
mSelectedRules.push_back(rule);
}
}
}
bool LintManager::isMatchFile(RuleBase *const rule)
{
// printf("rule: %s, isMatchFile: %s\n", rule->getName().c_str(),
// mFileName.c_str());
const std::set<std::string> &masks = rule->getMasks();
FOR_EACH (std::set<std::string>::const_iterator, it, masks)
{
// printf("check regexp: %s\n", (*it).c_str());
std::regex exp(*it);
if (std::regex_match (mFileName, exp))
{
// printf("matched\n");
return true;
}
}
return false;
}