khanat-code-old/code/ryzom/tools/stats_scan/char_scan_script.cpp
2013-11-13 20:31:08 +01:00

322 lines
9.3 KiB
C++

// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//-----------------------------------------------------------------------------
// includes
//-----------------------------------------------------------------------------
#include "nel/misc/variable.h"
#include "nel/misc/path.h"
#include "game_share/file_description_container.h"
#include "game_share/utils.h"
#include "char_scan_script.h"
//-----------------------------------------------------------------------------
// Namespaces
//-----------------------------------------------------------------------------
using namespace std;
using namespace NLMISC;
//-----------------------------------------------------------------------------
// Variables
//-----------------------------------------------------------------------------
CVariable<string> ScriptDirectory("variables", "ScriptDirectory", "Directory containing script files", string("./"), 0, true);
CVariable<string> OutputDirectory("variables", "OutputDirectory", "Directory containing output files", string("./"), 0, true);
//-------------------------------------------------------------------------------------------------
// methods CCharScanScript
//-------------------------------------------------------------------------------------------------
bool CCharScanScript::addScriptFile(const std::string& fileName)
{
std::string fullFileName=NLMISC::CPath::standardizePath(ScriptDirectory)+fileName;
// make sure the file exists
if (!NLMISC::CFile::fileExists(fullFileName))
{
nlwarning("script file not found: %s",fullFileName.c_str());
return false;
}
// make sure the file hasn't already been included previously
for (uint32 i=0;i<_ScriptFiles.size();++i)
{
if (_ScriptFiles[i].getFileName()==fullFileName)
{
nlwarning("attempt to include script file '%s' more than once",fullFileName.c_str());
return true;
}
}
// add & parse the new file
return vectAppend(_ScriptFiles).parseFile(fullFileName);
}
void CCharScanScript::applyToJob(CCharacterScanJob& job)
{
// iterate backwards over the script files in order to apply the most important files last
for (uint32 i=(uint32)_ScriptFiles.size();i--;)
{
_ScriptFiles[i].applyToJob(job);
}
}
//-------------------------------------------------------------------------------------------------
// methods CCharScanScriptFile
//-------------------------------------------------------------------------------------------------
bool CCharScanScriptFile::parseFile(const std::string& fileName, CCharScanScript* container)
{
_FileName= fileName;
// read the content of the input file
bool result;
NLMISC::CSString fileContent;
result=fileContent.readFromFile(fileName);
if (result==false)
{
nlwarning("Failed to read script file: %s",fileName.c_str());
return false;
}
// split the file into lines and execute them one by one
NLMISC::CVectorSString lines;
fileContent.splitLines(lines);
for (uint32 i=0;i<lines.size();++i)
{
// strip comments and leading and trailing blanks
CSString theLine= lines[i].replace("//","\xff").splitTo('\xff').strip();
if (theLine.empty())
continue;
CCharScanScriptCommandRegistry::getInstance()->execute(*this,theLine,container);
}
return true;
}
bool CCharScanScriptFile::applyToJob(CCharacterScanJob& job)
{
bool result=true;
// apply the file names
CFileDescriptionContainer fdc;
for (uint32 i=0;i<_InputFiles.size();++i)
{
fdc.addFileSpec(_InputFiles[i]);
}
job.addFiles(fdc);
// apply the filters
for (uint32 i=0;i<_Filters.size();++i)
{
ICharFilter* filter= CCharFilterFactory::getInstance()->build(_Filters[i]);
if (filter==NULL)
{
nlwarning("Failed to build filter description from line: %s",_Filters[i].c_str());
result=false;
continue;
}
job.addFilter(filter);
}
// apply the info extractors
for (uint32 i=0;i<_InfoExtractors.size();++i)
{
ICharInfoExtractor* infoExtractor= CCharInfoExtractorFactory::getInstance()->build(_InfoExtractors[i]);
if (infoExtractor==NULL)
{
nlwarning("Failed to build filter description from line: %s",_InfoExtractors[i].c_str());
result=false;
continue;
}
job.addInfoExtractor(infoExtractor);
}
// apply the output path
job.setOutputPath(_OutputPath);
return result;
}
const std::string& CCharScanScriptFile::getFileName() const
{
return _FileName;
}
const std::string& CCharScanScriptFile::getDescription() const
{
return _Description;
}
bool CCharScanScriptFile::setDescription(const std::string& description)
{
_Description= description;
return true;
}
bool CCharScanScriptFile::setOutputPath(const std::string& path)
{
_OutputPath= path;
return true;
}
bool CCharScanScriptFile::addFilter(const std::string& rawArgs)
{
_Filters.push_back(rawArgs);
return true;
}
bool CCharScanScriptFile::addInfoExtractor(const std::string& rawArgs)
{
_InfoExtractors.push_back(rawArgs);
return true;
}
bool CCharScanScriptFile::addInputFiles(const std::string& rawArgs)
{
_InputFiles.push_back(rawArgs);
return true;
}
//-------------------------------------------------------------------------------------------------
// methods CCharScanScriptCommandRegistry
//-------------------------------------------------------------------------------------------------
CCharScanScriptCommandRegistry* CCharScanScriptCommandRegistry::getInstance()
{
static CCharScanScriptCommandRegistry* ptr=NULL;
if (ptr==NULL)
ptr= new CCharScanScriptCommandRegistry;
return ptr;
}
void CCharScanScriptCommandRegistry::registerScriptCommand(NLMISC::CSmartPtr<ICharScanScriptCommand> scriptCommand)
{
// ensure that we don't have a name conflict with an existing script command
for (uint32 i=0;i<_ScriptCommands.size();++i)
{
nlassert(scriptCommand->getName()!=_ScriptCommands[i]->getName());
}
// add the new script command
_ScriptCommands.push_back(scriptCommand);
}
void CCharScanScriptCommandRegistry::displayScriptCommands(NLMISC::CLog* log)
{
uint32 longestName=4;
// iterate over the script commands to determine the length of the longest name
for (uint32 i=0;i<_ScriptCommands.size();++i)
{
std::string s= _ScriptCommands[i]->getName();
if (s.size()>longestName)
longestName=(uint32)s.size();
}
// iterate over the script commands displaying names and description
for (uint32 i=0;i<_ScriptCommands.size();++i)
{
log->displayNL("%-*s %s",longestName,_ScriptCommands[i]->getName(),_ScriptCommands[i]->getDescription());
}
}
bool CCharScanScriptCommandRegistry::execute(CCharScanScriptFile& scriptFile,const CSString& commandLine,CCharScanScript* container)
{
// split the command line into its constituent parts
CSString theCommand= commandLine.firstWordConst();
CSString theRawArgs= commandLine.tailFromFirstWord().strip();
CVectorSString theArgs;
theRawArgs.splitByOneOfSeparators(" \t",theArgs,false,false,false,false,true);
// try to locate and execute the given command
for (uint32 i=0;i<_ScriptCommands.size();++i)
{
if (theCommand==_ScriptCommands[i]->getName())
{
return _ScriptCommands[i]->execute(scriptFile,theArgs,theRawArgs,commandLine,container);
}
}
// we failed to find the command so bomb
nlwarning("Unknown script command '%s' in line: %s",theCommand.c_str(),commandLine.c_str());
return false;
}
//-----------------------------------------------------------------------------
// CHAR_SCAN_SCRIPT_COMMAND: instances
//-----------------------------------------------------------------------------
CHAR_SCAN_SCRIPT_COMMAND(description,"<description>","Set the description phrase for the script - displayed by the listScripts command")
{
if (rawArgs.strip().empty())
return false;
return scriptFile.setDescription(rawArgs);
}
CHAR_SCAN_SCRIPT_COMMAND(include,"<include_file_name>","Include another script file")
{
if (args.size()!=1)
return false;
if (container==NULL)
return true;
return container->addScriptFile(args[0]);
}
CHAR_SCAN_SCRIPT_COMMAND(inputFiles,"[<path>/]<file_spec>","Add a set of files to be parsed")
{
if (rawArgs.strip().empty())
return false;
return scriptFile.addInputFiles(rawArgs);
}
CHAR_SCAN_SCRIPT_COMMAND(filter,"<name> [<args>]","Add a filter to limit the set criteria to determine which files' content to reflect in output")
{
if (rawArgs.strip().empty())
return false;
return scriptFile.addFilter(rawArgs);
}
CHAR_SCAN_SCRIPT_COMMAND(infoExtactor,"<name> [<args>]","Add an info extractor")
{
if (rawArgs.strip().empty())
return false;
return scriptFile.addInfoExtractor(rawArgs);
}
CHAR_SCAN_SCRIPT_COMMAND(outputPath,"<path>","Set the directory to which the output will be written")
{
if (args.size()!=1)
return false;
return scriptFile.setOutputPath(args[0]);
}
//-----------------------------------------------------------------------------