diff options
Diffstat (limited to 'src/script')
-rw-r--r-- | src/script/script_info.cpp | 72 | ||||
-rw-r--r-- | src/script/script_info.hpp | 88 | ||||
-rw-r--r-- | src/script/script_scanner.cpp | 105 | ||||
-rw-r--r-- | src/script/script_scanner.hpp | 43 |
4 files changed, 308 insertions, 0 deletions
diff --git a/src/script/script_info.cpp b/src/script/script_info.cpp new file mode 100644 index 000000000..12df08ce5 --- /dev/null +++ b/src/script/script_info.cpp @@ -0,0 +1,72 @@ +/* $Id$ */ + +/** @file script_info.cpp Implementation of ScriptFileInfo. */ + +#include "../stdafx.h" + +#include <squirrel.h> +#include "squirrel.hpp" +#include "squirrel_helper.hpp" + +#include "script_info.hpp" +#include "script_scanner.hpp" + +ScriptFileInfo::~ScriptFileInfo() +{ + free((void *)this->author); + free((void *)this->name); + free((void *)this->short_name); + free((void *)this->description); + free((void *)this->date); + free((void *)this->instance_name); + free(this->main_script); + free(this->SQ_instance); +} + +bool ScriptFileInfo::CheckMethod(const char *name) const +{ + if (!this->engine->MethodExists(*this->SQ_instance, name)) { + char error[1024]; + snprintf(error, sizeof(error), "your info.nut/library.nut doesn't have the method '%s'", name); + this->engine->ThrowError(error); + return false; + } + return true; +} + +/* static */ SQInteger ScriptFileInfo::Constructor(HSQUIRRELVM vm, ScriptFileInfo *info) +{ + /* Set some basic info from the parent */ + info->SQ_instance = MallocT<SQObject>(1); + Squirrel::GetInstance(vm, info->SQ_instance, 2); + /* Make sure the instance stays alive over time */ + sq_addref(vm, info->SQ_instance); + ScriptScanner *scanner = (ScriptScanner *)Squirrel::GetGlobalPointer(vm); + info->engine = scanner->GetEngine(); + + static const char * const required_functions[] = { + "GetAuthor", + "GetName", + "GetShortName", + "GetDescription", + "GetVersion", + "GetDate", + "CreateInstance", + }; + for (size_t i = 0; i < lengthof(required_functions); i++) { + if (!info->CheckMethod(required_functions[i])) return SQ_ERROR; + } + + info->main_script = strdup(scanner->GetMainScript()); + + /* Cache the data the info file gives us. */ + if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetAuthor", &info->author)) return SQ_ERROR; + if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetName", &info->name)) return SQ_ERROR; + if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetShortName", &info->short_name)) return SQ_ERROR; + if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetDescription", &info->description)) return SQ_ERROR; + if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetDate", &info->date)) return SQ_ERROR; + if (!info->engine->CallIntegerMethod(*info->SQ_instance, "GetVersion", &info->version)) return SQ_ERROR; + if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "CreateInstance", &info->instance_name)) return SQ_ERROR; + + return 0; +} diff --git a/src/script/script_info.hpp b/src/script/script_info.hpp new file mode 100644 index 000000000..d34fd4cef --- /dev/null +++ b/src/script/script_info.hpp @@ -0,0 +1,88 @@ +/* $Id$ */ + +/** @file script_info.hpp ScriptInfo keeps track of all information of a script, like Author, Description, ... */ + +#ifndef SCRIPT_INFO +#define SCRIPT_INFO + +#include "../misc/countedptr.hpp" + +class ScriptFileInfo : public SimpleCountedObject { +public: + ScriptFileInfo() : + SQ_instance(NULL), + main_script(NULL), + author(NULL), + name(NULL), + short_name(NULL), + description(NULL), + date(NULL), + instance_name(NULL) + {} + ~ScriptFileInfo(); + + /** + * Get the Author of the script. + */ + const char *GetAuthor() const { return this->author; } + + /** + * Get the Name of the script. + */ + const char *GetName() const { return this->name; } + + /** + * Get the 4 character long short name of the script. + */ + const char *GetShortName() const { return this->short_name; } + + /** + * Get the description of the script. + */ + const char *GetDescription() const { return this->description; } + + /** + * Get the version of the script. + */ + int GetVersion() const { return this->version; } + + /** + * Get the last-modified date of the script. + */ + const char *GetDate() const { return this->date; } + + /** + * Get the name of the instance of the script to create. + */ + const char *GetInstanceName() const { return this->instance_name; } + + /** + * Get the filename of the main.nut script. + */ + const char *GetMainScript() const { return this->main_script; } + + /** + * Check if a given method exists. + */ + bool CheckMethod(const char *name) const; + + /** + * Process the creation of a FileInfo object. + */ + static SQInteger Constructor(HSQUIRRELVM vm, ScriptFileInfo *info); + +protected: + class Squirrel *engine; + HSQOBJECT *SQ_instance; +private: + char *main_script; + const char *author; + const char *name; + const char *short_name; + const char *description; + const char *date; + const char *instance_name; + int version; +}; + +#endif /* SCRIPT_INFO */ diff --git a/src/script/script_scanner.cpp b/src/script/script_scanner.cpp new file mode 100644 index 000000000..7b993889e --- /dev/null +++ b/src/script/script_scanner.cpp @@ -0,0 +1,105 @@ +/* $Id$ */ + +/** @file script_scanner.cpp Allows scanning for scripts. */ + +#include "../stdafx.h" +#include "../string_func.h" +#include "../fileio_func.h" +#include <sys/stat.h> + +#include <squirrel.h> +#include "../script/squirrel.hpp" +#include "script_info.hpp" +#include "script_scanner.hpp" + +void ScriptScanner::ScanDir(const char *dirname, const char *info_file_name) +{ + extern bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb); + extern bool FiosIsHiddenFile(const struct dirent *ent); + + char d_name[MAX_PATH]; + char temp_script[1024]; + struct stat sb; + struct dirent *dirent; + DIR *dir; + + dir = ttd_opendir(dirname); + /* Dir not found, so do nothing */ + if (dir == NULL) return; + + /* Walk all dirs trying to find a dir in which 'main.nut' exists */ + while ((dirent = readdir(dir)) != NULL) { + ttd_strlcpy(d_name, FS2OTTD(dirent->d_name), sizeof(d_name)); + + /* Valid file, not '.' or '..', not hidden */ + if (!FiosIsValidFile(dirname, dirent, &sb)) continue; + if (strcmp(d_name, ".") == 0 || strcmp(d_name, "..") == 0) continue; + if (FiosIsHiddenFile(dirent) && strncasecmp(d_name, PERSONAL_DIR, strlen(d_name)) != 0) continue; + + /* Create the full length dirname */ + ttd_strlcpy(temp_script, dirname, sizeof(temp_script)); + ttd_strlcat(temp_script, d_name, sizeof(temp_script)); + + if (S_ISREG(sb.st_mode)) { + /* Only .tar files are allowed */ + char *ext = strrchr(d_name, '.'); + if (ext == NULL || strcasecmp(ext, ".tar") != 0) continue; + + /* We always expect a directory in the TAR */ + const char *first_dir = FioTarFirstDir(temp_script); + if (first_dir == NULL) continue; + + ttd_strlcat(temp_script, PATHSEP, sizeof(temp_script)); + ttd_strlcat(temp_script, first_dir, sizeof(temp_script)); + FioTarAddLink(temp_script, first_dir); + } else if (!S_ISDIR(sb.st_mode)) { + /* Skip any other type of file */ + continue; + } + + /* Add an additional / where needed */ + if (temp_script[strlen(temp_script) - 1] != PATHSEPCHAR) ttd_strlcat(temp_script, PATHSEP, sizeof(temp_script)); + + char info_script[MAX_PATH]; + ttd_strlcpy(info_script, temp_script, sizeof(info_script)); + ttd_strlcpy(main_script, temp_script, sizeof(main_script)); + + /* Every script should contain an 'info.nut' and 'main.nut' file; else it is not a valid script */ + ttd_strlcat(info_script, info_file_name, sizeof(info_script)); + ttd_strlcat(main_script, "main.nut", sizeof(main_script)); + if (!FioCheckFileExists(info_script, NO_DIRECTORY) || !FioCheckFileExists(main_script, NO_DIRECTORY)) continue; + + /* We don't care if one of the other scripts failed to load. */ + this->engine->ResetCrashed(); + this->engine->LoadScript(info_script); + } + closedir(dir); +} + +void ScriptScanner::ScanScriptDir(const char *info_file_name, Subdirectory search_dir) +{ + char buf[MAX_PATH]; + Searchpath sp; + + extern void ScanForTarFiles(); + ScanForTarFiles(); + + FOR_ALL_SEARCHPATHS(sp) { + FioAppendDirectory(buf, MAX_PATH, sp, search_dir); + if (FileExists(buf)) this->ScanDir(buf, info_file_name); + } +} + +ScriptScanner::ScriptScanner() +{ + this->engine = new Squirrel(); + this->main_script[0] = '\0'; + + /* Mark this class as global pointer */ + this->engine->SetGlobalPointer(this); +} + +ScriptScanner::~ScriptScanner() +{ + delete this->engine; +} diff --git a/src/script/script_scanner.hpp b/src/script/script_scanner.hpp new file mode 100644 index 000000000..922e37202 --- /dev/null +++ b/src/script/script_scanner.hpp @@ -0,0 +1,43 @@ +/* $Id$ */ + +/** @file script_scanner.hpp Declarations of the class for the script scanner. */ + +#ifndef SCRIPT_SCANNER_HPP +#define SCRIPT_SCANNER_HPP + +#include "../fileio_type.h" + +class ScriptScanner { +public: + ScriptScanner(); + ~ScriptScanner(); + + /** + * Get the engine of the main squirrel handler (it indexes all available scripts). + */ + class Squirrel *GetEngine() { return this->engine; } + + /** + * Get the current main script the ScanDir is currently tracking. + */ + const char *GetMainScript() { return this->main_script; } + + /** + * Rescan for scripts. + * @param info_flie_name The name of the 'info.nut' file. + * @param search_dir The subdirecotry to search for scripts. + */ + void ScanScriptDir(const char *info_file_name, Subdirectory search_dir); + +private: + /** + * Scan a dir for scripts. + */ + void ScanDir(const char *dirname, const char *info_file_name); + +protected: + class Squirrel *engine; + char main_script[1024]; +}; + +#endif /* SCRIPT_SCANNER_HPP */ |