1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 16:57:16 +01:00
SqMod/source/Base/ScriptSrc.cpp

170 lines
5.2 KiB
C++
Raw Normal View History

// ------------------------------------------------------------------------------------------------
#include "Base/ScriptSrc.hpp"
// ------------------------------------------------------------------------------------------------
#include <cstdio>
#include <algorithm>
#include <stdexcept>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
/* ------------------------------------------------------------------------------------------------
* Helper class to ensure the file handle is closed regardless of the situation.
*/
class FileHandle
{
public:
// --------------------------------------------------------------------------------------------
std::FILE * mFile; // Handle to the opened file.
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
FileHandle(CSStr path)
: mFile(std::fopen(path, "rb"))
{
if (!mFile)
{
throw std::runtime_error(ToStrF("Unable to open script source (%s)", path));
}
}
/* --------------------------------------------------------------------------------------------
* Copy constructor. (disabled)
*/
FileHandle(const FileHandle & o) = delete;
/* --------------------------------------------------------------------------------------------
* Move constructor. (disabled)
*/
FileHandle(FileHandle && o) = delete;
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~FileHandle()
{
if (mFile)
{
std::fclose(mFile);
}
}
/* --------------------------------------------------------------------------------------------
* Copy assignment operator. (disabled)
*/
FileHandle & operator = (const FileHandle & o) = delete;
/* --------------------------------------------------------------------------------------------
* Move assignment operator. (disabled)
*/
FileHandle & operator = (FileHandle && o) = delete;
/* --------------------------------------------------------------------------------------------
* Implicit conversion to the managed file handle.
*/
operator std::FILE * ()
{
return mFile;
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to the managed file handle.
*/
operator std::FILE * () const
{
return mFile;
}
};
// ------------------------------------------------------------------------------------------------
void ScriptSrc::Process()
{
// Attempt to open the specified file
FileHandle fp(mPath.c_str());
// First 2 bytes of the file will tell if this is a compiled script
std::uint16_t tag;
// Read the first 2 bytes of the file and determine the file type
if (std::fread(&tag, 1, 2, fp) != 2 || tag == SQ_BYTECODE_STREAM_TAG)
{
return; // Probably an empty file or compiled script
}
// Go to the end of the file
std::fseek(fp, 0, SEEK_END);
// Calculate buffer size from beginning to current position
const LongI length = std::ftell(fp);
// Go back to the beginning
std::fseek(fp, 0, SEEK_SET);
// Allocate enough space to hold the file data
mData.resize(length, 0);
// Read the file contents into allocated data
std::fread(&mData[0], 1, length, fp);
// Where the last line ended
unsigned line = 0;
// Process the file data and locate new lines
for (String::const_iterator itr = mData.cbegin(); itr != mData.cend();)
{
// Is this a Unix style line ending?
if (*itr == '\n')
{
// Store the beginning of the line
mLine.push_back(line);
// Advance to the next line
line = std::distance(mData.cbegin(), ++itr);
}
// Is this a Windows style line ending?
else if (*itr == '\r')
{
if (*(++itr) == '\n')
{
// Store the beginning of the line
mLine.push_back(line);
// Advance to the next line
line = std::distance(mData.cbegin(), ++itr);
}
}
else
{
++itr;
}
}
// Should we add the last line as well?
if (line)
{
mLine.push_back(line);
}
// Specify that this script contains line information
mInfo = true;
}
// ------------------------------------------------------------------------------------------------
ScriptSrc::ScriptSrc(HSQUIRRELVM vm, String && path, bool delay, bool info)
: mExec(vm)
, mPath(std::move(path))
, mData()
, mLine()
, mInfo(info)
, mDelay(delay)
{
// Is the specified virtual machine invalid?
if (!vm)
{
throw std::runtime_error("Invalid virtual machine pointer");
}
// Is the specified path empty?
else if (mPath.empty())
{
throw std::runtime_error("Invalid or empty script path");
}
// Should we load the file contents for debugging purposes?
else if (mInfo)
{
Process();
}
}
} // Namespace:: SqMod