394 lines
11 KiB
C++
394 lines
11 KiB
C++
/*
|
|
* This file is part of the Colobot: Gold Edition source code
|
|
* Copyright (C) 2001-2015, Daniel Roux, EPSITEC SA & TerranovaTeam
|
|
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
|
*
|
|
* 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
|
|
* (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 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://gnu.org/licenses
|
|
*/
|
|
|
|
#include "CBot/stdlib/stdlib.h"
|
|
|
|
#include "CBot/CBot.h"
|
|
|
|
#include <memory>
|
|
#include <unordered_map>
|
|
#include <cassert>
|
|
|
|
namespace {
|
|
std::unique_ptr<CBotFileAccessHandler> g_fileHandler;
|
|
std::unordered_map<int, std::unique_ptr<CBotFile>> g_files;
|
|
int g_nextFileId = 1;
|
|
}
|
|
|
|
|
|
bool FileClassOpenFile(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
|
|
{
|
|
std::string mode;
|
|
|
|
// must be a character string
|
|
if ( pVar->GetType() != CBotTypString ) { Exception = CBotErrBadString; return false; }
|
|
|
|
std::string filename = pVar->GetValString();
|
|
|
|
// there may be a second parameter
|
|
pVar = pVar->GetNext();
|
|
if ( pVar != nullptr )
|
|
{
|
|
// recover mode
|
|
mode = pVar->GetValString();
|
|
if ( mode != "r" && mode != "w" ) { Exception = CBotErrBadParam; return false; }
|
|
|
|
// no third parameter
|
|
if ( pVar->GetNext() != nullptr ) { Exception = CBotErrOverParam; return false; }
|
|
}
|
|
|
|
// saves the file name
|
|
pVar = pThis->GetItem("filename");
|
|
pVar->SetValString(filename);
|
|
|
|
// retrieve the item "handle"
|
|
pVar = pThis->GetItem("handle");
|
|
// which must not be initialized
|
|
if ( pVar->IsDefined()) { Exception = CBotErrFileOpen; return false; }
|
|
|
|
if ( !mode.empty() )
|
|
{
|
|
// opens the requested file
|
|
assert(g_fileHandler != nullptr);
|
|
std::unique_ptr<CBotFile> file = g_fileHandler->OpenFile(filename, mode == "r" ? CBotFileAccessHandler::OpenMode::Read : CBotFileAccessHandler::OpenMode::Write);
|
|
|
|
if (!file->Opened()) { Exception = CBotErrFileOpen; return false; }
|
|
|
|
int fileHandle = g_nextFileId++;
|
|
g_files[fileHandle] = std::move(file);
|
|
|
|
// save the file handle
|
|
pVar = pThis->GetItem("handle");
|
|
pVar->SetValInt(fileHandle);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// constructor of the class
|
|
// get the filename as a parameter
|
|
|
|
// execution
|
|
bool rfconstruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user)
|
|
{
|
|
// accepts no parameters
|
|
if ( pVar == nullptr ) return true;
|
|
|
|
return FileClassOpenFile(pThis, pVar, pResult, Exception);
|
|
}
|
|
|
|
// compilation
|
|
CBotTypResult cfconstruct (CBotVar* pThis, CBotVar* &pVar)
|
|
{
|
|
// accepts no parameters
|
|
if ( pVar == nullptr ) return CBotTypResult( 0 );
|
|
|
|
// must be a character string
|
|
if ( pVar->GetType() != CBotTypString )
|
|
return CBotTypResult( CBotErrBadString );
|
|
|
|
// there may be a second parameter
|
|
pVar = pVar->GetNext();
|
|
if ( pVar != nullptr )
|
|
{
|
|
// which must be a string
|
|
if ( pVar->GetType() != CBotTypString )
|
|
return CBotTypResult( CBotErrBadString );
|
|
// no third parameter
|
|
if ( pVar->GetNext() != nullptr ) return CBotTypResult( CBotErrOverParam );
|
|
}
|
|
|
|
// the result is void (constructor)
|
|
return CBotTypResult( 0 );
|
|
}
|
|
|
|
|
|
// destructor of the class
|
|
|
|
// execution
|
|
bool rfdestruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user)
|
|
{
|
|
// retrieve the item "handle"
|
|
pVar = pThis->GetItem("handle");
|
|
|
|
if (!pVar->IsDefined()) return true; // file not opened
|
|
g_files.erase(pVar->GetValInt());
|
|
|
|
pVar->SetInit(CBotVar::InitType::IS_NAN);
|
|
return true;
|
|
}
|
|
|
|
|
|
// process FILE :: open
|
|
// get the r/w mode as a parameter
|
|
|
|
// execution
|
|
bool rfopen (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user)
|
|
{
|
|
// there must be a parameter
|
|
if ( pVar == nullptr ) { Exception = CBotErrLowParam; return false; }
|
|
|
|
bool result = FileClassOpenFile(pThis, pVar, pResult, Exception);
|
|
pResult->SetValInt(result);
|
|
return result;
|
|
}
|
|
|
|
// compilation
|
|
CBotTypResult cfopen (CBotVar* pThis, CBotVar* &pVar)
|
|
{
|
|
// there must be a parameter
|
|
if ( pVar == nullptr ) return CBotTypResult( CBotErrLowParam );
|
|
|
|
// which must be a string
|
|
if ( pVar->GetType() != CBotTypString )
|
|
return CBotTypResult( CBotErrBadString );
|
|
|
|
// there may be a second parameter
|
|
pVar = pVar->GetNext();
|
|
if ( pVar != nullptr )
|
|
{
|
|
// which must be a string
|
|
if ( pVar->GetType() != CBotTypString )
|
|
return CBotTypResult( CBotErrBadString );
|
|
|
|
// no third parameter
|
|
if ( pVar->GetNext() != nullptr ) return CBotTypResult( CBotErrOverParam );
|
|
}
|
|
|
|
// the result is bool
|
|
return CBotTypResult(CBotTypBoolean);
|
|
}
|
|
|
|
|
|
// process FILE :: close
|
|
|
|
// execeution
|
|
bool rfclose (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user)
|
|
{
|
|
// it shouldn't be any parameters
|
|
if (pVar != nullptr) { Exception = CBotErrOverParam; return false; }
|
|
|
|
// retrieve the item "handle"
|
|
pVar = pThis->GetItem("handle");
|
|
|
|
if (!pVar->IsDefined()) { Exception = CBotErrNotOpen; return false; }
|
|
|
|
int fileHandle = pVar->GetValInt();
|
|
|
|
const auto handleIter = g_files.find(fileHandle);
|
|
if (handleIter == g_files.end())
|
|
{
|
|
Exception = CBotErrNotOpen;
|
|
return false;
|
|
}
|
|
|
|
g_files.erase(handleIter);
|
|
|
|
pVar->SetInit(CBotVar::InitType::IS_NAN);
|
|
return true;
|
|
}
|
|
|
|
// compilation
|
|
CBotTypResult cfclose (CBotVar* pThis, CBotVar* &pVar)
|
|
{
|
|
// it shouldn't be any parameters
|
|
if ( pVar != nullptr ) return CBotTypResult( CBotErrOverParam );
|
|
|
|
// function returns a result "void"
|
|
return CBotTypResult( 0 );
|
|
}
|
|
|
|
// process FILE :: writeln
|
|
|
|
// execution
|
|
bool rfwrite (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user)
|
|
{
|
|
// there must be a parameter
|
|
if ( pVar == nullptr ) { Exception = CBotErrLowParam; return false; }
|
|
|
|
// which must be a character string
|
|
if ( pVar->GetType() != CBotTypString ) { Exception = CBotErrBadString; return false; }
|
|
|
|
std::string param = pVar->GetValString();
|
|
|
|
// retrieve the item "handle"
|
|
pVar = pThis->GetItem("handle");
|
|
|
|
if ( !pVar->IsDefined()) { Exception = CBotErrNotOpen; return false; }
|
|
|
|
int fileHandle = pVar->GetValInt();
|
|
|
|
const auto handleIter = g_files.find(fileHandle);
|
|
if (handleIter == g_files.end())
|
|
{
|
|
Exception = CBotErrNotOpen;
|
|
return false;
|
|
}
|
|
|
|
handleIter->second->Write(param + "\n");
|
|
|
|
// if an error occurs generate an exception
|
|
if ( handleIter->second->Errored() ) { Exception = CBotErrWrite; return false; }
|
|
|
|
return true;
|
|
}
|
|
|
|
// compilation
|
|
CBotTypResult cfwrite (CBotVar* pThis, CBotVar* &pVar)
|
|
{
|
|
// there must be a parameter
|
|
if ( pVar == nullptr ) return CBotTypResult( CBotErrLowParam );
|
|
|
|
// which must be a character string
|
|
if ( pVar->GetType() != CBotTypString ) return CBotTypResult( CBotErrBadString );
|
|
|
|
// no other parameter
|
|
if ( pVar->GetNext() != nullptr ) return CBotTypResult( CBotErrOverParam );
|
|
|
|
// the function returns a void result
|
|
return CBotTypResult( 0 );
|
|
}
|
|
|
|
// process FILE :: readln
|
|
|
|
// execution
|
|
bool rfread(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user)
|
|
{
|
|
// it shouldn't be any parameters
|
|
if (pVar != nullptr) { Exception = CBotErrOverParam; return false; }
|
|
|
|
// retrieve the item "handle"
|
|
pVar = pThis->GetItem("handle");
|
|
|
|
if (!pVar->IsDefined()) { Exception = CBotErrNotOpen; return false; }
|
|
|
|
int fileHandle = pVar->GetValInt();
|
|
|
|
const auto handleIter = g_files.find(fileHandle);
|
|
if (handleIter == g_files.end())
|
|
{
|
|
Exception = CBotErrNotOpen;
|
|
return false;
|
|
}
|
|
|
|
std::string line = handleIter->second->ReadLine();
|
|
|
|
// if an error occurs generate an exception
|
|
if ( handleIter->second->Errored() ) { Exception = CBotErrRead; return false; }
|
|
|
|
pResult->SetValString( line.c_str() );
|
|
|
|
return true;
|
|
}
|
|
|
|
// compilation
|
|
CBotTypResult cfread (CBotVar* pThis, CBotVar* &pVar)
|
|
{
|
|
// it should not be any parameter
|
|
if ( pVar != nullptr ) return CBotTypResult( CBotErrOverParam );
|
|
|
|
// function returns a result "string"
|
|
return CBotTypResult( CBotTypString );
|
|
}
|
|
// process FILE :: readln
|
|
|
|
|
|
// execution
|
|
bool rfeof (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user)
|
|
{
|
|
// it should not be any parameter
|
|
if ( pVar != nullptr ) { Exception = CBotErrOverParam; return false; }
|
|
|
|
// retrieve the item "handle"
|
|
pVar = pThis->GetItem("handle");
|
|
|
|
if ( !pVar->IsDefined()) { Exception = CBotErrNotOpen; return false; }
|
|
|
|
int fileHandle = pVar->GetValInt();
|
|
|
|
const auto handleIter = g_files.find(fileHandle);
|
|
if (handleIter == g_files.end())
|
|
{
|
|
Exception = CBotErrNotOpen;
|
|
return false;
|
|
}
|
|
|
|
pResult->SetValInt( handleIter->second->IsEOF() );
|
|
|
|
return true;
|
|
}
|
|
|
|
// compilation
|
|
CBotTypResult cfeof (CBotVar* pThis, CBotVar* &pVar)
|
|
{
|
|
// it shouldn't be any parameter
|
|
if ( pVar != nullptr ) return CBotTypResult( CBotErrOverParam );
|
|
|
|
// the function returns a boolean result
|
|
return CBotTypResult( CBotTypBoolean );
|
|
}
|
|
|
|
// Instruction "deletefile(filename)".
|
|
|
|
bool rDeleteFile(CBotVar* var, CBotVar* result, int& exception, void* user)
|
|
{
|
|
std::string filename = var->GetValString();
|
|
assert(g_fileHandler != nullptr);
|
|
return g_fileHandler->DeleteFile(filename);
|
|
}
|
|
|
|
|
|
void InitFileFunctions()
|
|
{
|
|
// create a class for file management
|
|
// the use is as follows:
|
|
// file canal( "NomFichier.txt" )
|
|
// canal.open( "r" ); // open for read
|
|
// s = canal.readln( ); // reads a line
|
|
// canal.close(); // close the file
|
|
|
|
// create the class FILE
|
|
CBotClass* bc = CBotClass::Create("file", nullptr);
|
|
// adds the component ".filename"
|
|
bc->AddItem("filename", CBotTypString);
|
|
// adds the component ".handle"
|
|
bc->AddItem("handle", CBotTypInt, CBotVar::ProtectionLevel::Private);
|
|
|
|
// define a constructor and a destructor
|
|
bc->AddFunction("file", rfconstruct, cfconstruct);
|
|
bc->AddFunction("~file", rfdestruct, nullptr);
|
|
|
|
// end of the methods associated
|
|
bc->AddFunction("open", rfopen, cfopen);
|
|
bc->AddFunction("close", rfclose, cfclose);
|
|
bc->AddFunction("writeln", rfwrite, cfwrite);
|
|
bc->AddFunction("readln", rfread, cfread);
|
|
bc->AddFunction("eof", rfeof, cfeof );
|
|
|
|
CBotProgram::AddFunction("deletefile", rDeleteFile, cString);
|
|
|
|
//m_pFuncFile = new CBotProgram( );
|
|
//std::stringArray ListFonctions;
|
|
//m_pFuncFile->Compile( "public file openfile(string name, string mode) {return new file(name, mode);}", ListFonctions);
|
|
//m_pFuncFile->SetIdent(-2); // restoreState in special identifier for this function
|
|
}
|
|
|
|
void SetFileAccessHandler(std::unique_ptr<CBotFileAccessHandler> fileHandler)
|
|
{
|
|
g_fileHandler = std::move(fileHandler);
|
|
} |