123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "platform/platform.h"
- #include "console/scriptFilename.h"
- #include "core/frameAllocator.h"
- #include "core/tSimpleHashTable.h"
- #include "core/strings/stringFunctions.h"
- #include "core/stringTable.h"
- #include "console/engineAPI.h"
- #include "console/compiler.h"
- namespace Con
- {
- //-----------------------------------------------------------------------------
- // Local Globals
- //-----------------------------------------------------------------------------
- struct PathExpando
- {
- StringTableEntry mPath;
- bool mIsToolsOnly;
- };
- static SimpleHashTable<PathExpando> sgPathExpandos(64, false);
- //-----------------------------------------------------------------------------
- // Global Functions
- //-----------------------------------------------------------------------------
- void setScriptPathExpando(const char *expando, const char *path, bool toolsOnly /*= false*/)
- {
- PathExpando *exp = sgPathExpandos.retreive(expando);
- if(exp)
- {
- exp->mPath = StringTable->insert(path);
- exp->mIsToolsOnly = toolsOnly;
- }
- else
- {
- exp = new PathExpando;
- exp->mPath = StringTable->insert(path);
- exp->mIsToolsOnly = toolsOnly;
- sgPathExpandos.insert(exp, expando);
- }
- }
- void removeScriptPathExpando(const char *expando)
- {
- PathExpando *exp = sgPathExpandos.remove(expando);
- if(exp)
- delete exp;
- }
- bool isScriptPathExpando(const char *expando)
- {
- PathExpando *exp = sgPathExpandos.retreive(expando);
- return ( exp != NULL);
- }
- //-----------------------------------------------------------------------------
- // [tom, 5/18/2006] FIXME: This needs some bounds checking
- bool expandToolScriptFilename(char *filename, U32 size, const char *src)
- {
- // [tom, 10/16/2006] Note: I am purposefully not early-outing here in the
- // same way the old code did as it is now possible that something could
- // be expanded if the name or mod is NULL. This was previously not the case.
- const StringTableEntry cbMod = CodeBlock::getCurrentCodeBlockModName();
- const StringTableEntry cbFullPath = CodeBlock::getCurrentCodeBlockFullPath();
- char varBuf[1024], modBuf[1024];
- const char *ptr = src;
- char *retPtr = filename;
- char *slash;
- const char *catPath = NULL;
- #ifndef TORQUE_DEBUG
- bool isTools = Con::isCurrentScriptToolScript();
- #endif
- // Check leading character
- switch(*ptr)
- {
- case '^':
- {
- // Variable
- const char *varPtr = ptr+1;
- char *insertPtr = varBuf;
- bool valid = true;
- while(*varPtr != '/')
- {
- if(*varPtr == 0)
- {
- valid = false;
- break;
- }
- *insertPtr++ = *varPtr++;
- }
- if(valid)
- {
- // Got a valid variable
- *insertPtr = 0;
- PathExpando *exp = sgPathExpandos.retreive(varBuf);
-
- if(exp == NULL)
- {
- Con::errorf("expandScriptFilename - Ignoring invalid path expando \"%s\"", varBuf);
- break;
- }
- #ifndef TORQUE_DEBUG
- // [tom, 12/13/2006] This stops tools expandos from working in the console,
- // which is useful behavior when debugging so I'm ifdefing this out for debug builds.
- if(! isTools && exp->mIsToolsOnly)
- {
- Con::errorf("expandScriptFilename - attempting to use tools only expando \"%s\" from outside of tools", varBuf);
- *filename = 0;
- return false;
- }
- #endif
- catPath = exp ? exp->mPath : "";
- // swallow the expando and the slash after the expando
- ptr += dStrlen(varBuf) + 1;
- if(*ptr == '/')
- ptr++;
- }
- }
- break;
- case '~':
- // Relative to mod
- if(cbMod && cbFullPath)
- {
- Platform::makeFullPathName(cbMod, modBuf, sizeof(modBuf));
- catPath = modBuf;
- }
- else
- {
- // Probably not a mod, so we'll use the ^game expando
- PathExpando *exp = sgPathExpandos.retreive("game");
- if(exp == NULL)
- {
- Con::errorf("expandScriptFilename - ~ expansion failed for mod and ^game when processing '%s'", src);
- break;
- }
- catPath = exp ? exp->mPath : "";
- }
- // swallow ~ and optional slash
- switch(ptr[1])
- {
- case '/': ptr += 2; break;
- default: ptr++;
- }
-
- break;
- case '.':
- // Relative to script directory
- if(cbFullPath)
- {
- dStrcpy(varBuf, cbFullPath, 1024);
- slash = dStrrchr(varBuf, '/');
- if(slash) *slash = 0;
- catPath = varBuf;
-
- // swallow dot and optional slash, but dont swallow .. relative path token
- switch(ptr[1])
- {
- case '.': break;
- case '/': ptr += 2; break;
- default: ptr++;
- }
- }
- break;
- }
- // [tom, 11/20/2006] Handing off to makeFullPathName() allows us to process .. correctly.
- Platform::makeFullPathName(ptr, retPtr, size, catPath);
- return true;
- }
- //-----------------------------------------------------------------------------
- bool expandOldScriptFilename(char *filename, U32 size, const char *src)
- {
- const StringTableEntry cbName = CodeBlock::getCurrentCodeBlockName();
- if (!cbName)
- {
- dStrcpy(filename, src, size);
- return true;
- }
- const char *slash;
- if (dStrncmp(src, "~/", 2) == 0)
- // tilde path means load from current codeblock/mod root
- slash = dStrchr(cbName, '/');
- else if (dStrncmp(src, "./", 2) == 0)
- // dot path means load from current codeblock/mod path
- slash = dStrrchr(cbName, '/');
- else if (dStrncmp(src, "^", 1) == 0)
- {
- Platform::makeFullPathName(src + 1, filename, size);
- return true;
- }
- else
- {
- // otherwise path must be fully specified
- if (dStrlen(src) > size)
- {
- Con::errorf("Buffer overflow attempting to expand filename: %s", src);
- *filename = 0;
- return false;
- }
- dStrcpy(filename, src, size);
- return true;
- }
- if (slash == NULL)
- {
- Con::errorf("Illegal CodeBlock path detected (no mod directory): %s", cbName);
- *filename = 0;
- return false;
- }
- U32 length = slash-cbName;
- if ((length+dStrlen(src)) > size)
- {
- Con::errorf("Buffer overflow attempting to expand filename: %s", src);
- *filename = 0;
- return false;
- }
- dStrncpy(filename, cbName, length);
- dStrcpy(filename+length, src+1, size - length);
- return true;
- }
- //-----------------------------------------------------------------------------
- bool expandScriptFilename(char *filename, U32 size, const char *src)
- {
- #ifndef TORQUE2D_TOOLS_FIXME
- return expandOldScriptFilename(filename, size, src);
- #else
- return expandToolScriptFilename(filename, size, src);
- #endif
- }
- //-----------------------------------------------------------------------------
- static StringTableEntry tryGetBasePath(const char *path, const char *base)
- {
- U32 len = dStrlen(base);
- if(dStrnicmp(path, base, len) == 0)
- {
- if(*(path + len) == '/') --len;
- return StringTable->insertn(path, len, true);
- }
- return NULL;
- }
- struct CollapseTest
- {
- const char *path;
- const char *replace;
- };
- bool collapseScriptFilename(char *filename, U32 size, const char *src)
- {
- PathExpando *tools = sgPathExpandos.retreive("tools");
- PathExpando *game = sgPathExpandos.retreive("game");
- CollapseTest test[]=
- {
- { game ? game->mPath : NULL, "~" },
- { tools ? tools->mPath : NULL, "^tools" },
- { Platform::getCurrentDirectory(), "" },
- { Platform::getMainDotCsDir(), "" },
- { NULL, NULL }
- };
- for(S32 i = 0;!(test[i].path == NULL && test[i].replace == NULL);++i)
- {
- if(test[i].path == NULL) continue;
- StringTableEntry base = tryGetBasePath(src, test[i].path);
- if(base == NULL)
- continue;
- StringTableEntry rel = Platform::makeRelativePathName(src, test[i].path);
-
- *filename = 0;
- if(*test[i].replace)
- dSprintf(filename, size, "%s/", test[i].replace);
- dStrcat(filename, rel, size);
- return true;
- }
- dStrncpy(filename, src, size - 1);
- filename[size-1] = 0;
- return true;
- }
- //-----------------------------------------------------------------------------
- } // end namespace Con
- //-----------------------------------------------------------------------------
- // Console Functions
- //-----------------------------------------------------------------------------
- DefineEngineFunction(expandFilename, const char*, (const char* filename),,
- "@brief Grabs the full path of a specified file\n\n"
- "@param filename Name of the local file to locate\n"
- "@return String containing the full filepath on disk\n"
- "@ingroup FileSystem")
- {
- static const U32 bufSize = 1024;
- char* ret = Con::getReturnBuffer(bufSize);
- Con::expandScriptFilename(ret, bufSize, filename);
- return ret;
- }
- DefineEngineFunction(expandOldFilename, const char*, (const char* filename),,
- "@brief Retrofits a filepath that uses old Torque style\n\n"
- "@return String containing filepath with new formatting\n"
- "@ingroup FileSystem")
- {
- static const U32 bufSize = 1024;
- char* ret = Con::getReturnBuffer(bufSize);
- Con::expandOldScriptFilename(ret, bufSize, filename);
- return ret;
- }
- //-----------------------------------------------------------------------------
- // Tool Functions
- //-----------------------------------------------------------------------------
- ConsoleToolFunction(collapseFilename, const char*, 2, 2, "(string filename)"
- "@internal Editor use only")
- {
- TORQUE_UNUSED(argc);
- static const U32 bufSize = 1024;
- char* ret = Con::getReturnBuffer( bufSize );
- Con::collapseScriptFilename(ret, bufSize, argv[1]);
- return ret;
- }
- ConsoleToolFunction(setScriptPathExpando, void, 3, 4, "(string expando, string path[, bool toolsOnly])"
- "@internal Editor use only")
- {
- if(argc == 4)
- Con::setScriptPathExpando(argv[1], argv[2], dAtob(argv[3]));
- else
- Con::setScriptPathExpando(argv[1], argv[2]);
- }
- ConsoleToolFunction(removeScriptPathExpando, void, 2, 2, "(string expando)"
- "@internal Editor use only")
- {
- Con::removeScriptPathExpando(argv[1]);
- }
- ConsoleToolFunction(isScriptPathExpando, bool, 2, 2, "(string expando)"
- "@internal Editor use only")
- {
- return Con::isScriptPathExpando(argv[1]);
- }
|