diff --git a/cbp/Module.cbp b/cbp/Module.cbp index 27bb62f5..ffd08044 100644 --- a/cbp/Module.cbp +++ b/cbp/Module.cbp @@ -445,6 +445,8 @@ + + diff --git a/source/Base/ScriptSrc.cpp b/source/Base/ScriptSrc.cpp new file mode 100644 index 00000000..20e03f6f --- /dev/null +++ b/source/Base/ScriptSrc.cpp @@ -0,0 +1,160 @@ +// ------------------------------------------------------------------------------------------------ +#include "Base/ScriptSrc.hpp" + +// ------------------------------------------------------------------------------------------------ +#include +#include +#include + +// ------------------------------------------------------------------------------------------------ +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); + } +} + +// ------------------------------------------------------------------------------------------------ +ScriptSrc::ScriptSrc(HSQUIRRELVM vm, const String & path, bool info) + : mExec(vm) + , mPath(path) + , mData() + , mLine() +{ + // Is the specified path empty? + if (mPath.empty()) + { + throw std::runtime_error("Invalid or empty script path"); + } + // Should we load the file contents for debugging purposes? + if (info) + { + Process(); + } +} + +} // Namespace:: SqMod diff --git a/source/Base/ScriptSrc.hpp b/source/Base/ScriptSrc.hpp new file mode 100644 index 00000000..e935da9e --- /dev/null +++ b/source/Base/ScriptSrc.hpp @@ -0,0 +1,75 @@ +#ifndef _BASE_SCRIPTSRC_HPP_ +#define _BASE_SCRIPTSRC_HPP_ + +// ------------------------------------------------------------------------------------------------ +#include "Base/Utility.hpp" + +// ------------------------------------------------------------------------------------------------ +#include +#include + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ +class Core; + +/* ------------------------------------------------------------------------------------------------ + * Hold a information about loaded scripts as it's contents and executable code. +*/ +class ScriptSrc +{ + // -------------------------------------------------------------------------------------------- + friend class Core; + +public: + + // -------------------------------------------------------------------------------------------- + typedef std::vector< Uint32 > Line; + + // -------------------------------------------------------------------------------------------- + Script mExec; // Reference to the script object. + String mPath; // Path to the script file. + String mData; // The contents of the script file. + Line mLine; // List of lines of code in the data. + +private: + + /* -------------------------------------------------------------------------------------------- + * Read file contents and calculate information about the lines of code. + */ + void Process(); + + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + ScriptSrc(HSQUIRRELVM vm, const String & path, bool info = false); + +public: + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + ScriptSrc(const ScriptSrc & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + ScriptSrc(ScriptSrc && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + ScriptSrc & operator = (const ScriptSrc & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + ScriptSrc & operator = (ScriptSrc && o) = default; + +}; + + +} // Namespace:: SqMod + +#endif // _BASE_SCRIPTSRC_HPP_