consoleInternal.cpp 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include <unordered_map>
  23. #include "platform/platform.h"
  24. #include "console/console.h"
  25. #include "console/ast.h"
  26. #include "core/tAlgorithm.h"
  27. #include "core/strings/findMatch.h"
  28. #include "console/consoleInternal.h"
  29. #include "core/stream/fileStream.h"
  30. #include "console/compiler.h"
  31. #include "console/engineAPI.h"
  32. //#define DEBUG_SPEW
  33. #define ST_INIT_SIZE 15
  34. static char scratchBuffer[1024];
  35. U32 Namespace::mCacheSequence = 0;
  36. DataChunker Namespace::mCacheAllocator;
  37. DataChunker Namespace::mAllocator;
  38. Namespace *Namespace::mNamespaceList = NULL;
  39. Namespace *Namespace::mGlobalNamespace = NULL;
  40. namespace std
  41. {
  42. template<> struct hash<std::pair<StringTableEntry, StringTableEntry>>
  43. {
  44. typedef std::pair<StringTableEntry, StringTableEntry> argument_type;
  45. typedef size_t result_type;
  46. result_type operator()(argument_type const& s) const
  47. {
  48. return HashPointer(s.first) ^ (HashPointer(s.second) << 1);
  49. }
  50. };
  51. };
  52. std::unordered_map<std::pair<StringTableEntry, StringTableEntry>, Namespace*> gNamespaceCache;
  53. bool canTabComplete(const char *prevText, const char *bestMatch,
  54. const char *newText, S32 baseLen, bool fForward)
  55. {
  56. // test if it matches the first baseLen chars:
  57. if (dStrnicmp(newText, prevText, baseLen))
  58. return false;
  59. if (fForward)
  60. {
  61. if (!bestMatch)
  62. return dStricmp(newText, prevText) > 0;
  63. else
  64. return (dStricmp(newText, prevText) > 0) &&
  65. (dStricmp(newText, bestMatch) < 0);
  66. }
  67. else
  68. {
  69. if (dStrlen(prevText) == (U32)baseLen)
  70. {
  71. // look for the 'worst match'
  72. if (!bestMatch)
  73. return dStricmp(newText, prevText) > 0;
  74. else
  75. return dStricmp(newText, bestMatch) > 0;
  76. }
  77. else
  78. {
  79. if (!bestMatch)
  80. return (dStricmp(newText, prevText) < 0);
  81. else
  82. return (dStricmp(newText, prevText) < 0) &&
  83. (dStricmp(newText, bestMatch) > 0);
  84. }
  85. }
  86. }
  87. //---------------------------------------------------------------
  88. //
  89. // Dictionary functions
  90. //
  91. //---------------------------------------------------------------
  92. struct StringValue
  93. {
  94. S32 size;
  95. char *val;
  96. operator char *() { return val; }
  97. StringValue &operator=(const char *string);
  98. StringValue() { size = 0; val = NULL; }
  99. ~StringValue() { dFree(val); }
  100. };
  101. StringValue & StringValue::operator=(const char *string)
  102. {
  103. if (!val)
  104. {
  105. val = dStrdup(string);
  106. size = dStrlen(val);
  107. }
  108. else
  109. {
  110. S32 len = dStrlen(string);
  111. if (len < size)
  112. dStrcpy(val, string, size);
  113. else
  114. {
  115. size = len;
  116. dFree(val);
  117. val = dStrdup(string);
  118. }
  119. }
  120. return *this;
  121. }
  122. static S32 QSORT_CALLBACK varCompare(const void* a, const void* b)
  123. {
  124. return dStricmp((*((Dictionary::Entry **) a))->name, (*((Dictionary::Entry **) b))->name);
  125. }
  126. void Dictionary::exportVariables(const char *varString, const char *fileName, bool append)
  127. {
  128. const char *searchStr = varString;
  129. Vector<Entry *> sortList(__FILE__, __LINE__);
  130. for (S32 i = 0; i < hashTable->size; i++)
  131. {
  132. Entry *walk = hashTable->data[i];
  133. while (walk)
  134. {
  135. if (FindMatch::isMatch((char *)searchStr, (char *)walk->name))
  136. sortList.push_back(walk);
  137. walk = walk->nextEntry;
  138. }
  139. }
  140. if (!sortList.size())
  141. return;
  142. dQsort((void *)&sortList[0], sortList.size(), sizeof(Entry *), varCompare);
  143. Vector<Entry *>::iterator s;
  144. char expandBuffer[1024];
  145. FileStream *strm = NULL;
  146. if (fileName)
  147. {
  148. if ((strm = FileStream::createAndOpen(fileName, append ? Torque::FS::File::ReadWrite : Torque::FS::File::Write)) == NULL)
  149. {
  150. Con::errorf(ConsoleLogEntry::General, "Unable to open file '%s for writing.", fileName);
  151. return;
  152. }
  153. if (append)
  154. strm->setPosition(strm->getStreamSize());
  155. }
  156. char buffer[1024];
  157. const char *cat = fileName ? "\r\n" : "";
  158. for (s = sortList.begin(); s != sortList.end(); s++)
  159. {
  160. switch ((*s)->value.type)
  161. {
  162. case ConsoleValue::TypeInternalInt:
  163. dSprintf(buffer, sizeof(buffer), "%s = %d;%s", (*s)->name, (*s)->value.ival, cat);
  164. break;
  165. case ConsoleValue::TypeInternalFloat:
  166. dSprintf(buffer, sizeof(buffer), "%s = %g;%s", (*s)->name, (*s)->value.fval, cat);
  167. break;
  168. default:
  169. expandEscape(expandBuffer, (*s)->getStringValue());
  170. dSprintf(buffer, sizeof(buffer), "%s = \"%s\";%s", (*s)->name, expandBuffer, cat);
  171. break;
  172. }
  173. if (strm)
  174. strm->write(dStrlen(buffer), buffer);
  175. else
  176. Con::printf("%s", buffer);
  177. }
  178. if (strm)
  179. delete strm;
  180. }
  181. void Dictionary::exportVariables(const char *varString, Vector<String> *names, Vector<String> *values)
  182. {
  183. const char *searchStr = varString;
  184. Vector<Entry *> sortList(__FILE__, __LINE__);
  185. for (S32 i = 0; i < hashTable->size; i++)
  186. {
  187. Entry *walk = hashTable->data[i];
  188. while (walk)
  189. {
  190. if (FindMatch::isMatch((char*)searchStr, (char*)walk->name))
  191. sortList.push_back(walk);
  192. walk = walk->nextEntry;
  193. }
  194. }
  195. if (!sortList.size())
  196. return;
  197. dQsort((void *)&sortList[0], sortList.size(), sizeof(Entry *), varCompare);
  198. if (names)
  199. names->reserve(sortList.size());
  200. if (values)
  201. values->reserve(sortList.size());
  202. char expandBuffer[1024];
  203. Vector<Entry *>::iterator s;
  204. for (s = sortList.begin(); s != sortList.end(); s++)
  205. {
  206. if (names)
  207. names->push_back(String((*s)->name));
  208. if (values)
  209. {
  210. switch ((*s)->value.type)
  211. {
  212. case ConsoleValue::TypeInternalInt:
  213. values->push_back(String::ToString((*s)->value.ival));
  214. break;
  215. case ConsoleValue::TypeInternalFloat:
  216. values->push_back(String::ToString((*s)->value.fval));
  217. break;
  218. default:
  219. expandEscape(expandBuffer, (*s)->getStringValue());
  220. values->push_back(expandBuffer);
  221. break;
  222. }
  223. }
  224. }
  225. }
  226. void Dictionary::deleteVariables(const char *varString)
  227. {
  228. const char *searchStr = varString;
  229. for (S32 i = 0; i < hashTable->size; i++)
  230. {
  231. Entry *walk = hashTable->data[i];
  232. while (walk)
  233. {
  234. Entry *matchedEntry = (FindMatch::isMatch((char *)searchStr, (char *)walk->name)) ? walk : NULL;
  235. walk = walk->nextEntry;
  236. if (matchedEntry)
  237. remove(matchedEntry); // assumes remove() is a stable remove (will not reorder entries on remove)
  238. }
  239. }
  240. }
  241. U32 HashPointer(StringTableEntry ptr)
  242. {
  243. return (U32)(((dsize_t)ptr) >> 2);
  244. }
  245. Dictionary::Entry *Dictionary::lookup(StringTableEntry name)
  246. {
  247. Entry *walk = hashTable->data[HashPointer(name) % hashTable->size];
  248. while (walk)
  249. {
  250. if (walk->name == name)
  251. return walk;
  252. else
  253. walk = walk->nextEntry;
  254. }
  255. return NULL;
  256. }
  257. Dictionary::Entry *Dictionary::add(StringTableEntry name)
  258. {
  259. // Try to find an existing match.
  260. //printf("Add Variable %s\n", name);
  261. Entry* ret = lookup(name);
  262. if (ret)
  263. return ret;
  264. // Rehash if the table get's too crowded. Be aware that this might
  265. // modify a table that we don't own.
  266. hashTable->count++;
  267. if (hashTable->count > hashTable->size * 2)
  268. {
  269. // Allocate a new table.
  270. const U32 newTableSize = hashTable->size * 4 - 1;
  271. Entry** newTableData = new Entry*[newTableSize];
  272. dMemset(newTableData, 0, newTableSize * sizeof(Entry*));
  273. // Move the entries over.
  274. for (U32 i = 0; i < hashTable->size; ++i)
  275. for (Entry* entry = hashTable->data[i]; entry != NULL; )
  276. {
  277. Entry* next = entry->nextEntry;
  278. U32 index = HashPointer(entry->name) % newTableSize;
  279. entry->nextEntry = newTableData[index];
  280. newTableData[index] = entry;
  281. entry = next;
  282. }
  283. // Switch the tables.
  284. delete[] hashTable->data;
  285. hashTable->data = newTableData;
  286. hashTable->size = newTableSize;
  287. }
  288. #ifdef DEBUG_SPEW
  289. Platform::outputDebugString("[ConsoleInternal] Adding entry '%s'", name);
  290. #endif
  291. // Add the new entry.
  292. ret = hashTable->mChunker.alloc();
  293. constructInPlace(ret, name);
  294. U32 idx = HashPointer(name) % hashTable->size;
  295. ret->nextEntry = hashTable->data[idx];
  296. hashTable->data[idx] = ret;
  297. return ret;
  298. }
  299. // deleteVariables() assumes remove() is a stable remove (will not reorder entries on remove)
  300. void Dictionary::remove(Dictionary::Entry *ent)
  301. {
  302. Entry **walk = &hashTable->data[HashPointer(ent->name) % hashTable->size];
  303. while (*walk != ent)
  304. walk = &((*walk)->nextEntry);
  305. #ifdef DEBUG_SPEW
  306. Platform::outputDebugString("[ConsoleInternal] Removing entry '%s'", ent->name);
  307. #endif
  308. *walk = (ent->nextEntry);
  309. destructInPlace(ent);
  310. hashTable->mChunker.free(ent);
  311. hashTable->count--;
  312. }
  313. Dictionary::Dictionary()
  314. : hashTable(NULL),
  315. #pragma warning( disable : 4355 )
  316. ownHashTable(this), // Warning with VC++ but this is safe.
  317. #pragma warning( default : 4355 )
  318. exprState(NULL),
  319. scopeName(NULL),
  320. scopeNamespace(NULL),
  321. code(NULL),
  322. ip(0)
  323. {
  324. }
  325. void Dictionary::setState(ExprEvalState *state, Dictionary* ref)
  326. {
  327. exprState = state;
  328. if (ref)
  329. {
  330. hashTable = ref->hashTable;
  331. return;
  332. }
  333. if (!ownHashTable.data)
  334. {
  335. ownHashTable.count = 0;
  336. ownHashTable.size = ST_INIT_SIZE;
  337. ownHashTable.data = new Entry *[ownHashTable.size];
  338. dMemset(ownHashTable.data, 0, ownHashTable.size * sizeof(Entry*));
  339. }
  340. hashTable = &ownHashTable;
  341. }
  342. Dictionary::~Dictionary()
  343. {
  344. reset();
  345. if (ownHashTable.data)
  346. delete[] ownHashTable.data;
  347. }
  348. void Dictionary::reset()
  349. {
  350. if (hashTable && hashTable->owner != this)
  351. {
  352. hashTable = NULL;
  353. return;
  354. }
  355. for (U32 i = 0; i < ownHashTable.size; ++i)
  356. {
  357. Entry* walk = ownHashTable.data[i];
  358. while (walk)
  359. {
  360. Entry* temp = walk->nextEntry;
  361. destructInPlace(walk);
  362. walk = temp;
  363. }
  364. }
  365. dMemset(ownHashTable.data, 0, ownHashTable.size * sizeof(Entry*));
  366. ownHashTable.mChunker.freeBlocks(true);
  367. ownHashTable.count = 0;
  368. hashTable = NULL;
  369. scopeName = NULL;
  370. scopeNamespace = NULL;
  371. code = NULL;
  372. ip = 0;
  373. }
  374. const char *Dictionary::tabComplete(const char *prevText, S32 baseLen, bool fForward)
  375. {
  376. S32 i;
  377. const char *bestMatch = NULL;
  378. for (i = 0; i < hashTable->size; i++)
  379. {
  380. Entry *walk = hashTable->data[i];
  381. while (walk)
  382. {
  383. if (canTabComplete(prevText, bestMatch, walk->name, baseLen, fForward))
  384. bestMatch = walk->name;
  385. walk = walk->nextEntry;
  386. }
  387. }
  388. return bestMatch;
  389. }
  390. char *typeValueEmpty = "";
  391. Dictionary::Entry::Entry(StringTableEntry in_name)
  392. {
  393. name = in_name;
  394. value.type = ConsoleValue::TypeInternalString;
  395. notify = NULL;
  396. nextEntry = NULL;
  397. mUsage = NULL;
  398. mIsConstant = false;
  399. mNext = NULL;
  400. // NOTE: This is data inside a nameless
  401. // union, so we don't need to init the rest.
  402. value.init();
  403. }
  404. Dictionary::Entry::~Entry()
  405. {
  406. value.cleanup();
  407. if (notify)
  408. delete notify;
  409. }
  410. const char *Dictionary::getVariable(StringTableEntry name, bool *entValid)
  411. {
  412. Entry *ent = lookup(name);
  413. if (ent)
  414. {
  415. if (entValid)
  416. *entValid = true;
  417. return ent->getStringValue();
  418. }
  419. if (entValid)
  420. *entValid = false;
  421. // Warn users when they access a variable that isn't defined.
  422. if (gWarnUndefinedScriptVariables)
  423. Con::warnf(" *** Accessed undefined variable '%s'", name);
  424. return "";
  425. }
  426. void ConsoleValue::setStringValue(const char * value)
  427. {
  428. if (value == NULL) value = typeValueEmpty;
  429. if (type <= ConsoleValue::TypeInternalString)
  430. {
  431. // Let's not remove empty-string-valued global vars from the dict.
  432. // If we remove them, then they won't be exported, and sometimes
  433. // it could be necessary to export such a global. There are very
  434. // few empty-string global vars so there's no performance-related
  435. // need to remove them from the dict.
  436. /*
  437. if(!value[0] && name[0] == '$')
  438. {
  439. gEvalState.globalVars.remove(this);
  440. return;
  441. }
  442. */
  443. if (value == typeValueEmpty)
  444. {
  445. if (bufferLen > 0)
  446. {
  447. dFree(sval);
  448. bufferLen = 0;
  449. }
  450. sval = typeValueEmpty;
  451. fval = 0.f;
  452. ival = 0;
  453. type = TypeInternalString;
  454. return;
  455. }
  456. U32 stringLen = dStrlen(value);
  457. // If it's longer than 256 bytes, it's certainly not a number.
  458. //
  459. // (This decision may come back to haunt you. Shame on you if it
  460. // does.)
  461. if (stringLen < 256)
  462. {
  463. fval = dAtof(value);
  464. ival = dAtoi(value);
  465. }
  466. else
  467. {
  468. fval = 0.f;
  469. ival = 0;
  470. }
  471. // may as well pad to the next cache line
  472. U32 newLen = ((stringLen + 1) + 15) & ~15;
  473. if (bufferLen == 0)
  474. sval = (char *)dMalloc(newLen);
  475. else if (newLen > bufferLen)
  476. sval = (char *)dRealloc(sval, newLen);
  477. type = TypeInternalString;
  478. bufferLen = newLen;
  479. dStrcpy(sval, value, newLen);
  480. }
  481. else
  482. Con::setData(type, dataPtr, 0, 1, &value, enumTable);
  483. }
  484. void ConsoleValue::setStackStringValue(const char *value)
  485. {
  486. if (value == NULL) value = typeValueEmpty;
  487. if (type <= ConsoleValue::TypeInternalString)
  488. {
  489. // sval might still be temporarily present so we need to check and free it
  490. if (bufferLen > 0)
  491. {
  492. dFree(sval);
  493. bufferLen = 0;
  494. }
  495. if (value == typeValueEmpty)
  496. {
  497. sval = typeValueEmpty;
  498. fval = 0.f;
  499. ival = 0;
  500. type = TypeInternalString;
  501. return;
  502. }
  503. U32 stringLen = dStrlen(value);
  504. if (stringLen < 256)
  505. {
  506. fval = dAtof(value);
  507. ival = dAtoi(value);
  508. }
  509. else
  510. {
  511. fval = 0.f;
  512. ival = 0;
  513. }
  514. type = TypeInternalStackString;
  515. sval = (char*)value;
  516. bufferLen = 0;
  517. }
  518. else
  519. Con::setData(type, dataPtr, 0, 1, &value, enumTable);
  520. }
  521. void ConsoleValue::setStringStackPtrValue(StringStackPtr ptrValue)
  522. {
  523. if (type <= ConsoleValue::TypeInternalString)
  524. {
  525. const char *value = StringStackPtrRef(ptrValue).getPtr(&STR);
  526. if (bufferLen > 0)
  527. {
  528. dFree(sval);
  529. bufferLen = 0;
  530. }
  531. U32 stringLen = dStrlen(value);
  532. if (stringLen < 256)
  533. {
  534. fval = dAtof(value);
  535. ival = dAtoi(value);
  536. }
  537. else
  538. {
  539. fval = 0.f;
  540. ival = 0;
  541. }
  542. type = TypeInternalStringStackPtr;
  543. sval = (char*)(value - STR.mBuffer);
  544. bufferLen = 0;
  545. }
  546. else
  547. {
  548. const char *value = StringStackPtrRef(ptrValue).getPtr(&STR);
  549. Con::setData(type, dataPtr, 0, 1, &value, enumTable);
  550. }
  551. }
  552. S32 Dictionary::getIntVariable(StringTableEntry name, bool *entValid)
  553. {
  554. Entry *ent = lookup(name);
  555. if (ent)
  556. {
  557. if (entValid)
  558. *entValid = true;
  559. return ent->getIntValue();
  560. }
  561. if (entValid)
  562. *entValid = false;
  563. return 0;
  564. }
  565. F32 Dictionary::getFloatVariable(StringTableEntry name, bool *entValid)
  566. {
  567. Entry *ent = lookup(name);
  568. if (ent)
  569. {
  570. if (entValid)
  571. *entValid = true;
  572. return ent->getFloatValue();
  573. }
  574. if (entValid)
  575. *entValid = false;
  576. return 0;
  577. }
  578. void Dictionary::setVariable(StringTableEntry name, const char *value)
  579. {
  580. Entry *ent = add(name);
  581. if (!value)
  582. value = "";
  583. ent->setStringValue(value);
  584. }
  585. Dictionary::Entry* Dictionary::addVariable(const char *name,
  586. S32 type,
  587. void *dataPtr,
  588. const char* usage)
  589. {
  590. AssertFatal(type >= 0, "Dictionary::addVariable - Got bad type!");
  591. if (name[0] != '$')
  592. {
  593. scratchBuffer[0] = '$';
  594. dStrcpy(scratchBuffer + 1, name, 1023);
  595. name = scratchBuffer;
  596. }
  597. Entry *ent = add(StringTable->insert(name));
  598. if (ent->value.type <= ConsoleValue::TypeInternalString &&
  599. ent->value.bufferLen > 0)
  600. dFree(ent->value.sval);
  601. ent->value.type = type;
  602. ent->value.dataPtr = dataPtr;
  603. ent->mUsage = usage;
  604. // Fetch enum table, if any.
  605. ConsoleBaseType* conType = ConsoleBaseType::getType(type);
  606. AssertFatal(conType, "Dictionary::addVariable - invalid console type");
  607. ent->value.enumTable = conType->getEnumTable();
  608. return ent;
  609. }
  610. bool Dictionary::removeVariable(StringTableEntry name)
  611. {
  612. if (Entry *ent = lookup(name))
  613. {
  614. remove(ent);
  615. return true;
  616. }
  617. return false;
  618. }
  619. void Dictionary::addVariableNotify(const char *name, const Con::NotifyDelegate &callback)
  620. {
  621. Entry *ent = lookup(StringTable->insert(name));
  622. if (!ent)
  623. return;
  624. if (!ent->notify)
  625. ent->notify = new Entry::NotifySignal();
  626. ent->notify->notify(callback);
  627. }
  628. void Dictionary::removeVariableNotify(const char *name, const Con::NotifyDelegate &callback)
  629. {
  630. Entry *ent = lookup(StringTable->insert(name));
  631. if (ent && ent->notify)
  632. ent->notify->remove(callback);
  633. }
  634. void Dictionary::validate()
  635. {
  636. AssertFatal(ownHashTable.owner == this,
  637. "Dictionary::validate() - Dictionary not owner of own hashtable!");
  638. }
  639. void ExprEvalState::pushFrame(StringTableEntry frameName, Namespace *ns)
  640. {
  641. #ifdef DEBUG_SPEW
  642. validate();
  643. Platform::outputDebugString("[ConsoleInternal] Pushing new frame for '%s' at %i",
  644. frameName, mStackDepth);
  645. #endif
  646. if (mStackDepth + 1 > stack.size())
  647. {
  648. #ifdef DEBUG_SPEW
  649. Platform::outputDebugString("[ConsoleInternal] Growing stack by one frame");
  650. #endif
  651. stack.push_back(new Dictionary);
  652. }
  653. Dictionary& newFrame = *(stack[mStackDepth]);
  654. newFrame.setState(this);
  655. newFrame.scopeName = frameName;
  656. newFrame.scopeNamespace = ns;
  657. mStackDepth++;
  658. currentVariable = NULL;
  659. AssertFatal(!newFrame.getCount(), "ExprEvalState::pushFrame - Dictionary not empty!");
  660. #ifdef DEBUG_SPEW
  661. validate();
  662. #endif
  663. }
  664. void ExprEvalState::popFrame()
  665. {
  666. AssertFatal(mStackDepth > 0, "ExprEvalState::popFrame - Stack Underflow!");
  667. #ifdef DEBUG_SPEW
  668. validate();
  669. Platform::outputDebugString("[ConsoleInternal] Popping %sframe at %i",
  670. getCurrentFrame().isOwner() ? "" : "shared ", mStackDepth - 1);
  671. #endif
  672. mStackDepth--;
  673. stack[mStackDepth]->reset();
  674. currentVariable = NULL;
  675. #ifdef DEBUG_SPEW
  676. validate();
  677. #endif
  678. }
  679. void ExprEvalState::pushFrameRef(S32 stackIndex)
  680. {
  681. AssertFatal(stackIndex >= 0 && stackIndex < stack.size(), "You must be asking for a valid frame!");
  682. #ifdef DEBUG_SPEW
  683. validate();
  684. Platform::outputDebugString("[ConsoleInternal] Cloning frame from %i to %i",
  685. stackIndex, mStackDepth);
  686. #endif
  687. if (mStackDepth + 1 > stack.size())
  688. {
  689. #ifdef DEBUG_SPEW
  690. Platform::outputDebugString("[ConsoleInternal] Growing stack by one frame");
  691. #endif
  692. stack.push_back(new Dictionary);
  693. }
  694. Dictionary& newFrame = *(stack[mStackDepth]);
  695. newFrame.setState(this, stack[stackIndex]);
  696. mStackDepth++;
  697. currentVariable = NULL;
  698. #ifdef DEBUG_SPEW
  699. validate();
  700. #endif
  701. }
  702. ExprEvalState::ExprEvalState()
  703. {
  704. VECTOR_SET_ASSOCIATION(stack);
  705. globalVars.setState(this);
  706. thisObject = NULL;
  707. traceOn = false;
  708. currentVariable = NULL;
  709. mStackDepth = 0;
  710. stack.reserve(64);
  711. mShouldReset = false;
  712. mResetLocked = false;
  713. copyVariable = NULL;
  714. }
  715. ExprEvalState::~ExprEvalState()
  716. {
  717. // Delete callframes.
  718. while (!stack.empty())
  719. {
  720. delete stack.last();
  721. stack.decrement();
  722. }
  723. }
  724. void ExprEvalState::validate()
  725. {
  726. AssertFatal(mStackDepth <= stack.size(),
  727. "ExprEvalState::validate() - Stack depth pointing beyond last stack frame!");
  728. for (U32 i = 0; i < stack.size(); ++i)
  729. stack[i]->validate();
  730. }
  731. DefineEngineFunction(backtrace, void, (), ,
  732. "@brief Prints the scripting call stack to the console log.\n\n"
  733. "Used to trace functions called from within functions. Can help discover what functions were called "
  734. "(and not yet exited) before the current point in scripts.\n\n"
  735. "@ingroup Debugging")
  736. {
  737. U32 totalSize = 1;
  738. for (U32 i = 0; i < gEvalState.getStackDepth(); i++)
  739. {
  740. if (gEvalState.stack[i]->scopeNamespace && gEvalState.stack[i]->scopeNamespace->mEntryList->mPackage)
  741. totalSize += dStrlen(gEvalState.stack[i]->scopeNamespace->mEntryList->mPackage) + 2;
  742. if (gEvalState.stack[i]->scopeName)
  743. totalSize += dStrlen(gEvalState.stack[i]->scopeName) + 3;
  744. if (gEvalState.stack[i]->scopeNamespace && gEvalState.stack[i]->scopeNamespace->mName)
  745. totalSize += dStrlen(gEvalState.stack[i]->scopeNamespace->mName) + 2;
  746. }
  747. char *buf = Con::getReturnBuffer(totalSize);
  748. buf[0] = 0;
  749. for (U32 i = 0; i < gEvalState.getStackDepth(); i++)
  750. {
  751. dStrcat(buf, "->", totalSize);
  752. if (gEvalState.stack[i]->scopeNamespace && gEvalState.stack[i]->scopeNamespace->mEntryList->mPackage)
  753. {
  754. dStrcat(buf, "[", totalSize);
  755. dStrcat(buf, gEvalState.stack[i]->scopeNamespace->mEntryList->mPackage, totalSize);
  756. dStrcat(buf, "]", totalSize);
  757. }
  758. if (gEvalState.stack[i]->scopeNamespace && gEvalState.stack[i]->scopeNamespace->mName)
  759. {
  760. dStrcat(buf, gEvalState.stack[i]->scopeNamespace->mName, totalSize);
  761. dStrcat(buf, "::", totalSize);
  762. }
  763. if (gEvalState.stack[i]->scopeName)
  764. dStrcat(buf, gEvalState.stack[i]->scopeName, totalSize);
  765. }
  766. Con::printf("BackTrace: %s", buf);
  767. }
  768. Namespace::Entry::Entry()
  769. {
  770. mCode = NULL;
  771. mType = InvalidFunctionType;
  772. mUsage = NULL;
  773. mHeader = NULL;
  774. mNamespace = NULL;
  775. cb.mStringCallbackFunc = NULL;
  776. mFunctionLineNumber = 0;
  777. mFunctionName = StringTable->EmptyString();
  778. mFunctionOffset = 0;
  779. mMinArgs = 0;
  780. mMaxArgs = 0;
  781. mNext = NULL;
  782. mPackage = StringTable->EmptyString();
  783. mToolOnly = false;
  784. }
  785. void Namespace::Entry::clear()
  786. {
  787. if (mCode)
  788. {
  789. mCode->decRefCount();
  790. mCode = NULL;
  791. }
  792. // Clean up usage strings generated for script functions.
  793. if ((mType == Namespace::Entry::ConsoleFunctionType) && mUsage)
  794. {
  795. dFree(mUsage);
  796. mUsage = NULL;
  797. }
  798. }
  799. Namespace::Namespace()
  800. {
  801. mPackage = NULL;
  802. mUsage = NULL;
  803. mCleanUpUsage = false;
  804. mName = NULL;
  805. mParent = NULL;
  806. mNext = NULL;
  807. mEntryList = NULL;
  808. mHashSize = 0;
  809. mHashTable = 0;
  810. mHashSequence = 0;
  811. mRefCountToParent = 0;
  812. mClassRep = 0;
  813. lastUsage = NULL;
  814. }
  815. Namespace::~Namespace()
  816. {
  817. clearEntries();
  818. if (mUsage && mCleanUpUsage)
  819. {
  820. dFree(mUsage);
  821. mUsage = NULL;
  822. mCleanUpUsage = false;
  823. }
  824. }
  825. void Namespace::clearEntries()
  826. {
  827. for (Entry *walk = mEntryList; walk; walk = walk->mNext)
  828. walk->clear();
  829. }
  830. Namespace *Namespace::find(StringTableEntry name, StringTableEntry package)
  831. {
  832. if (name == NULL && package == NULL)
  833. return mGlobalNamespace;
  834. auto pair = std::make_pair(name, package);
  835. auto pos = gNamespaceCache.find(pair);
  836. if (pos != gNamespaceCache.end())
  837. return pos->second;
  838. Namespace *ret = (Namespace *)mAllocator.alloc(sizeof(Namespace));
  839. constructInPlace(ret);
  840. ret->mPackage = package;
  841. ret->mName = name;
  842. ret->mNext = mNamespaceList;
  843. mNamespaceList = ret;
  844. // insert into namespace cache.
  845. gNamespaceCache[pair] = ret;
  846. return ret;
  847. }
  848. bool Namespace::unlinkClass(Namespace *parent)
  849. {
  850. AssertFatal(mPackage == NULL, "Namespace::unlinkClass - Must not be called on a namespace coming from a package!");
  851. // Skip additions to this namespace coming from packages.
  852. Namespace* walk = getPackageRoot();
  853. // Make sure "parent" is the direct parent namespace.
  854. if (parent != NULL && walk->mParent && walk->mParent != parent)
  855. {
  856. Con::errorf(ConsoleLogEntry::General, "Namespace::unlinkClass - cannot unlink namespace parent linkage for %s for %s.",
  857. walk->mName, walk->mParent->mName);
  858. return false;
  859. }
  860. // Decrease the reference count. Note that we do this on
  861. // the bottom-most namespace, i.e. the one guaranteed not
  862. // to come from a package.
  863. mRefCountToParent--;
  864. AssertFatal(mRefCountToParent >= 0, "Namespace::unlinkClass - reference count to parent is less than 0");
  865. // Unlink if the count dropped to zero.
  866. if (mRefCountToParent == 0)
  867. {
  868. walk->mParent = NULL;
  869. trashCache();
  870. }
  871. return true;
  872. }
  873. bool Namespace::classLinkTo(Namespace *parent)
  874. {
  875. Namespace* walk = getPackageRoot();
  876. if (walk->mParent && walk->mParent != parent)
  877. {
  878. Con::errorf(ConsoleLogEntry::General, "Error: cannot change namespace parent linkage of %s from %s to %s.",
  879. walk->mName, walk->mParent->mName, parent->mName);
  880. return false;
  881. }
  882. trashCache();
  883. walk->mParent = parent;
  884. mRefCountToParent++;
  885. return true;
  886. }
  887. void Namespace::buildHashTable()
  888. {
  889. if (mHashSequence == mCacheSequence)
  890. return;
  891. if (!mEntryList && mParent)
  892. {
  893. mParent->buildHashTable();
  894. mHashTable = mParent->mHashTable;
  895. mHashSize = mParent->mHashSize;
  896. mHashSequence = mCacheSequence;
  897. return;
  898. }
  899. U32 entryCount = 0;
  900. Namespace * ns;
  901. for (ns = this; ns; ns = ns->mParent)
  902. for (Entry *walk = ns->mEntryList; walk; walk = walk->mNext)
  903. if (lookupRecursive(walk->mFunctionName) == walk)
  904. entryCount++;
  905. mHashSize = entryCount + (entryCount >> 1) + 1;
  906. if (!(mHashSize & 1))
  907. mHashSize++;
  908. mHashTable = (Entry **)mCacheAllocator.alloc(sizeof(Entry *) * mHashSize);
  909. for (U32 i = 0; i < mHashSize; i++)
  910. mHashTable[i] = NULL;
  911. for (ns = this; ns; ns = ns->mParent)
  912. {
  913. for (Entry *walk = ns->mEntryList; walk; walk = walk->mNext)
  914. {
  915. U32 index = HashPointer(walk->mFunctionName) % mHashSize;
  916. while (mHashTable[index] && mHashTable[index]->mFunctionName != walk->mFunctionName)
  917. {
  918. index++;
  919. if (index >= mHashSize)
  920. index = 0;
  921. }
  922. if (!mHashTable[index])
  923. mHashTable[index] = walk;
  924. }
  925. }
  926. mHashSequence = mCacheSequence;
  927. }
  928. void Namespace::getUniqueEntryLists(Namespace *other, VectorPtr<Entry *> *outThisList, VectorPtr<Entry *> *outOtherList)
  929. {
  930. // All namespace entries in the common ACR should be
  931. // ignored when checking for duplicate entry names.
  932. static VectorPtr<Namespace::Entry *> commonEntries;
  933. commonEntries.clear();
  934. AbstractClassRep *commonACR = mClassRep->getCommonParent(other->mClassRep);
  935. commonACR->getNameSpace()->getEntryList(&commonEntries);
  936. // Make life easier
  937. VectorPtr<Namespace::Entry *> &thisEntries = *outThisList;
  938. VectorPtr<Namespace::Entry *> &compEntries = *outOtherList;
  939. // Clear, just in case they aren't
  940. thisEntries.clear();
  941. compEntries.clear();
  942. getEntryList(&thisEntries);
  943. other->getEntryList(&compEntries);
  944. // Run through all of the entries in the common ACR, and remove them from
  945. // the other two entry lists
  946. for (NamespaceEntryListIterator itr = commonEntries.begin(); itr != commonEntries.end(); itr++)
  947. {
  948. // Check this entry list
  949. for (NamespaceEntryListIterator thisItr = thisEntries.begin(); thisItr != thisEntries.end(); thisItr++)
  950. {
  951. if (*thisItr == *itr)
  952. {
  953. thisEntries.erase(thisItr);
  954. break;
  955. }
  956. }
  957. // Same check for component entry list
  958. for (NamespaceEntryListIterator compItr = compEntries.begin(); compItr != compEntries.end(); compItr++)
  959. {
  960. if (*compItr == *itr)
  961. {
  962. compEntries.erase(compItr);
  963. break;
  964. }
  965. }
  966. }
  967. }
  968. void Namespace::init()
  969. {
  970. // create the global namespace
  971. mGlobalNamespace = (Namespace *)mAllocator.alloc(sizeof(Namespace));
  972. constructInPlace(mGlobalNamespace);
  973. mGlobalNamespace->mPackage = NULL;
  974. mGlobalNamespace->mName = NULL;
  975. mGlobalNamespace->mNext = NULL;
  976. mNamespaceList = mGlobalNamespace;
  977. // Insert into namespace cache.
  978. gNamespaceCache[std::make_pair(mGlobalNamespace->mName, mGlobalNamespace->mPackage)] = mGlobalNamespace;
  979. }
  980. Namespace *Namespace::global()
  981. {
  982. return mGlobalNamespace;
  983. }
  984. void Namespace::shutdown()
  985. {
  986. // The data chunker will release all memory in one go
  987. // without calling destructors, so we do this manually here.
  988. for (Namespace *walk = mNamespaceList; walk; walk = walk->mNext)
  989. walk->~Namespace();
  990. }
  991. void Namespace::trashCache()
  992. {
  993. mCacheSequence++;
  994. mCacheAllocator.freeBlocks();
  995. }
  996. const char *Namespace::tabComplete(const char *prevText, S32 baseLen, bool fForward)
  997. {
  998. if (mHashSequence != mCacheSequence)
  999. buildHashTable();
  1000. const char *bestMatch = NULL;
  1001. for (U32 i = 0; i < mHashSize; i++)
  1002. if (mHashTable[i] && canTabComplete(prevText, bestMatch, mHashTable[i]->mFunctionName, baseLen, fForward))
  1003. bestMatch = mHashTable[i]->mFunctionName;
  1004. return bestMatch;
  1005. }
  1006. Namespace::Entry *Namespace::lookupRecursive(StringTableEntry name)
  1007. {
  1008. for (Namespace *ns = this; ns; ns = ns->mParent)
  1009. for (Entry *walk = ns->mEntryList; walk; walk = walk->mNext)
  1010. if (walk->mFunctionName == name)
  1011. return walk;
  1012. return NULL;
  1013. }
  1014. Namespace::Entry *Namespace::lookup(StringTableEntry name)
  1015. {
  1016. if (mHashSequence != mCacheSequence)
  1017. buildHashTable();
  1018. U32 index = HashPointer(name) % mHashSize;
  1019. while (mHashTable[index] && mHashTable[index]->mFunctionName != name)
  1020. {
  1021. index++;
  1022. if (index >= mHashSize)
  1023. index = 0;
  1024. }
  1025. return mHashTable[index];
  1026. }
  1027. static S32 QSORT_CALLBACK compareEntries(const void* a, const void* b)
  1028. {
  1029. const Namespace::Entry* fa = *((Namespace::Entry**)a);
  1030. const Namespace::Entry* fb = *((Namespace::Entry**)b);
  1031. return dStricmp(fa->mFunctionName, fb->mFunctionName);
  1032. }
  1033. void Namespace::getEntryList(VectorPtr<Entry *> *vec)
  1034. {
  1035. if (mHashSequence != mCacheSequence)
  1036. buildHashTable();
  1037. for (U32 i = 0; i < mHashSize; i++)
  1038. if (mHashTable[i])
  1039. vec->push_back(mHashTable[i]);
  1040. dQsort(vec->address(), vec->size(), sizeof(Namespace::Entry *), compareEntries);
  1041. }
  1042. Namespace::Entry *Namespace::createLocalEntry(StringTableEntry name)
  1043. {
  1044. for (Entry *walk = mEntryList; walk; walk = walk->mNext)
  1045. {
  1046. if (walk->mFunctionName == name)
  1047. {
  1048. walk->clear();
  1049. return walk;
  1050. }
  1051. }
  1052. Entry *ent = (Entry *)mAllocator.alloc(sizeof(Entry));
  1053. constructInPlace(ent);
  1054. ent->mNamespace = this;
  1055. ent->mFunctionName = name;
  1056. ent->mNext = mEntryList;
  1057. ent->mPackage = mPackage;
  1058. ent->mToolOnly = false;
  1059. mEntryList = ent;
  1060. return ent;
  1061. }
  1062. void Namespace::addFunction(StringTableEntry name, CodeBlock *cb, U32 functionOffset, const char* usage, U32 lineNumber)
  1063. {
  1064. Entry *ent = createLocalEntry(name);
  1065. trashCache();
  1066. ent->mUsage = usage;
  1067. ent->mCode = cb;
  1068. ent->mFunctionOffset = functionOffset;
  1069. ent->mCode->incRefCount();
  1070. ent->mType = Entry::ConsoleFunctionType;
  1071. ent->mFunctionLineNumber = lineNumber;
  1072. }
  1073. void Namespace::addCommand(StringTableEntry name, StringCallback cb, const char *usage, S32 minArgs, S32 maxArgs, bool isToolOnly, ConsoleFunctionHeader* header)
  1074. {
  1075. Entry *ent = createLocalEntry(name);
  1076. trashCache();
  1077. ent->mUsage = usage;
  1078. ent->mHeader = header;
  1079. ent->mMinArgs = minArgs;
  1080. ent->mMaxArgs = maxArgs;
  1081. ent->mToolOnly = isToolOnly;
  1082. ent->mType = Entry::StringCallbackType;
  1083. ent->cb.mStringCallbackFunc = cb;
  1084. }
  1085. void Namespace::addCommand(StringTableEntry name, IntCallback cb, const char *usage, S32 minArgs, S32 maxArgs, bool isToolOnly, ConsoleFunctionHeader* header)
  1086. {
  1087. Entry *ent = createLocalEntry(name);
  1088. trashCache();
  1089. ent->mUsage = usage;
  1090. ent->mHeader = header;
  1091. ent->mMinArgs = minArgs;
  1092. ent->mMaxArgs = maxArgs;
  1093. ent->mToolOnly = isToolOnly;
  1094. ent->mType = Entry::IntCallbackType;
  1095. ent->cb.mIntCallbackFunc = cb;
  1096. }
  1097. void Namespace::addCommand(StringTableEntry name, VoidCallback cb, const char *usage, S32 minArgs, S32 maxArgs, bool isToolOnly, ConsoleFunctionHeader* header)
  1098. {
  1099. Entry *ent = createLocalEntry(name);
  1100. trashCache();
  1101. ent->mUsage = usage;
  1102. ent->mHeader = header;
  1103. ent->mMinArgs = minArgs;
  1104. ent->mMaxArgs = maxArgs;
  1105. ent->mToolOnly = isToolOnly;
  1106. ent->mType = Entry::VoidCallbackType;
  1107. ent->cb.mVoidCallbackFunc = cb;
  1108. }
  1109. void Namespace::addCommand(StringTableEntry name, FloatCallback cb, const char *usage, S32 minArgs, S32 maxArgs, bool isToolOnly, ConsoleFunctionHeader* header)
  1110. {
  1111. Entry *ent = createLocalEntry(name);
  1112. trashCache();
  1113. ent->mUsage = usage;
  1114. ent->mHeader = header;
  1115. ent->mMinArgs = minArgs;
  1116. ent->mMaxArgs = maxArgs;
  1117. ent->mToolOnly = isToolOnly;
  1118. ent->mType = Entry::FloatCallbackType;
  1119. ent->cb.mFloatCallbackFunc = cb;
  1120. }
  1121. void Namespace::addCommand(StringTableEntry name, BoolCallback cb, const char *usage, S32 minArgs, S32 maxArgs, bool isToolOnly, ConsoleFunctionHeader* header)
  1122. {
  1123. Entry *ent = createLocalEntry(name);
  1124. trashCache();
  1125. ent->mUsage = usage;
  1126. ent->mHeader = header;
  1127. ent->mMinArgs = minArgs;
  1128. ent->mMaxArgs = maxArgs;
  1129. ent->mToolOnly = isToolOnly;
  1130. ent->mType = Entry::BoolCallbackType;
  1131. ent->cb.mBoolCallbackFunc = cb;
  1132. }
  1133. void Namespace::addScriptCallback(const char *funcName, const char *usage, ConsoleFunctionHeader* header)
  1134. {
  1135. static U32 uid = 0;
  1136. char buffer[1024];
  1137. char lilBuffer[32];
  1138. dStrcpy(buffer, funcName, 1024);
  1139. dSprintf(lilBuffer, 32, "_%d_cb", uid++);
  1140. dStrcat(buffer, lilBuffer, 1024);
  1141. Entry *ent = createLocalEntry(StringTable->insert(buffer));
  1142. trashCache();
  1143. ent->mUsage = usage;
  1144. ent->mHeader = header;
  1145. ent->mMinArgs = -2;
  1146. ent->mMaxArgs = -3;
  1147. ent->mType = Entry::ScriptCallbackType;
  1148. ent->cb.mCallbackName = funcName;
  1149. }
  1150. void Namespace::markGroup(const char* name, const char* usage)
  1151. {
  1152. static U32 uid = 0;
  1153. char buffer[1024];
  1154. char lilBuffer[32];
  1155. dStrcpy(buffer, name, 1024);
  1156. dSprintf(lilBuffer, 32, "_%d", uid++);
  1157. dStrcat(buffer, lilBuffer, 1024);
  1158. Entry *ent = createLocalEntry(StringTable->insert(buffer));
  1159. trashCache();
  1160. if (usage != NULL)
  1161. lastUsage = (char*)(ent->mUsage = usage);
  1162. else
  1163. ent->mUsage = lastUsage;
  1164. ent->mMinArgs = -1; // Make sure it explodes if somehow we run this entry.
  1165. ent->mMaxArgs = -2;
  1166. ent->mType = Entry::GroupMarker;
  1167. ent->cb.mGroupName = name;
  1168. }
  1169. extern S32 executeBlock(StmtNode *block, ExprEvalState *state);
  1170. ConsoleValueRef Namespace::Entry::execute(S32 argc, ConsoleValueRef *argv, ExprEvalState *state)
  1171. {
  1172. STR.clearFunctionOffset();
  1173. if (mType == ConsoleFunctionType)
  1174. {
  1175. if (mFunctionOffset)
  1176. {
  1177. return mCode->exec(mFunctionOffset, argv[0], mNamespace, argc, argv, false, mPackage);
  1178. }
  1179. else
  1180. {
  1181. return ConsoleValueRef();
  1182. }
  1183. }
  1184. #ifndef TORQUE_DEBUG
  1185. // [tom, 12/13/2006] This stops tools functions from working in the console,
  1186. // which is useful behavior when debugging so I'm ifdefing this out for debug builds.
  1187. if (mToolOnly && !Con::isCurrentScriptToolScript())
  1188. {
  1189. Con::errorf(ConsoleLogEntry::Script, "%s::%s - attempting to call tools only function from outside of tools", mNamespace->mName, mFunctionName);
  1190. return ConsoleValueRef();
  1191. }
  1192. #endif
  1193. if ((mMinArgs && argc < mMinArgs) || (mMaxArgs && argc > mMaxArgs))
  1194. {
  1195. Con::warnf(ConsoleLogEntry::Script, "%s::%s - wrong number of arguments.", mNamespace->mName, mFunctionName);
  1196. Con::warnf(ConsoleLogEntry::Script, "usage: %s", mUsage);
  1197. return ConsoleValueRef();
  1198. }
  1199. switch (mType)
  1200. {
  1201. case StringCallbackType:
  1202. return ConsoleValueRef::fromValue(CSTK.pushStackString(cb.mStringCallbackFunc(state->thisObject, argc, argv)));
  1203. case IntCallbackType:
  1204. return ConsoleValueRef::fromValue(CSTK.pushUINT((U32)cb.mBoolCallbackFunc(state->thisObject, argc, argv)));
  1205. case FloatCallbackType:
  1206. return ConsoleValueRef::fromValue(CSTK.pushFLT((U32)cb.mBoolCallbackFunc(state->thisObject, argc, argv)));
  1207. case VoidCallbackType:
  1208. cb.mVoidCallbackFunc(state->thisObject, argc, argv);
  1209. return ConsoleValueRef();
  1210. case BoolCallbackType:
  1211. return ConsoleValueRef::fromValue(CSTK.pushUINT((U32)cb.mBoolCallbackFunc(state->thisObject, argc, argv)));
  1212. }
  1213. return ConsoleValueRef();
  1214. }
  1215. //-----------------------------------------------------------------------------
  1216. // Doc string code.
  1217. namespace {
  1218. /// Scan the given usage string for an argument list description. With the
  1219. /// old console macros, these were usually included as the first part of the
  1220. /// usage string.
  1221. bool sFindArgumentListSubstring(const char* usage, const char*& start, const char*& end)
  1222. {
  1223. if (!usage)
  1224. return false;
  1225. const char* ptr = usage;
  1226. while (*ptr && *ptr != '(' && *ptr != '\n') // Only scan first line of usage string.
  1227. {
  1228. // Stop on the first alphanumeric character as we expect
  1229. // argument lists to precede descriptions.
  1230. if (dIsalnum(*ptr))
  1231. return false;
  1232. ptr++;
  1233. }
  1234. if (*ptr != '(')
  1235. return false;
  1236. start = ptr;
  1237. ptr++;
  1238. bool inString = false;
  1239. U32 nestingCount = 0;
  1240. while (*ptr && (*ptr != ')' || nestingCount > 0 || inString))
  1241. {
  1242. if (*ptr == '(')
  1243. nestingCount++;
  1244. else if (*ptr == ')')
  1245. nestingCount--;
  1246. else if (*ptr == '"')
  1247. inString = !inString;
  1248. else if (*ptr == '\\' && ptr[1] == '"')
  1249. ptr++;
  1250. ptr++;
  1251. }
  1252. if (*ptr)
  1253. ptr++;
  1254. end = ptr;
  1255. return true;
  1256. }
  1257. ///
  1258. void sParseList(const char* str, Vector< String >& outList)
  1259. {
  1260. // Skip the initial '( '.
  1261. const char* ptr = str;
  1262. while (*ptr && dIsspace(*ptr))
  1263. ptr++;
  1264. if (*ptr == '(')
  1265. {
  1266. ptr++;
  1267. while (*ptr && dIsspace(*ptr))
  1268. ptr++;
  1269. }
  1270. // Parse out list items.
  1271. while (*ptr && *ptr != ')')
  1272. {
  1273. // Find end of element.
  1274. const char* start = ptr;
  1275. bool inString = false;
  1276. U32 nestingCount = 0;
  1277. while (*ptr && ((*ptr != ')' && *ptr != ',') || nestingCount > 0 || inString))
  1278. {
  1279. if (*ptr == '(')
  1280. nestingCount++;
  1281. else if (*ptr == ')')
  1282. nestingCount--;
  1283. else if (*ptr == '"')
  1284. inString = !inString;
  1285. else if (*ptr == '\\' && ptr[1] == '"')
  1286. ptr++;
  1287. ptr++;
  1288. }
  1289. // Backtrack to remove trailing whitespace.
  1290. const char* end = ptr;
  1291. if (*end == ',' || *end == ')')
  1292. end--;
  1293. while (end > start && dIsspace(*end))
  1294. end--;
  1295. if (*end)
  1296. end++;
  1297. // Add to list.
  1298. if (start != end)
  1299. outList.push_back(String(start, end - start));
  1300. // Skip comma and whitespace.
  1301. if (*ptr == ',')
  1302. ptr++;
  1303. while (*ptr && dIsspace(*ptr))
  1304. ptr++;
  1305. }
  1306. }
  1307. ///
  1308. void sGetArgNameAndType(const String& str, String& outType, String& outName)
  1309. {
  1310. if (!str.length())
  1311. {
  1312. outType = String::EmptyString;
  1313. outName = String::EmptyString;
  1314. return;
  1315. }
  1316. // Find first non-ID character from right.
  1317. S32 index = str.length() - 1;
  1318. while (index >= 0 && (dIsalnum(str[index]) || str[index] == '_'))
  1319. index--;
  1320. const U32 nameStartIndex = index + 1;
  1321. // Find end of type name by skipping rightmost whitespace inwards.
  1322. while (index >= 0 && dIsspace(str[index]))
  1323. index--;
  1324. //
  1325. outName = String(&((const char*)str)[nameStartIndex]);
  1326. outType = String(str, index + 1);
  1327. }
  1328. /// Return the type name to show in documentation for the given C++ type.
  1329. const char* sGetDocTypeString(const char* nativeType)
  1330. {
  1331. if (dStrncmp(nativeType, "const ", 6) == 0)
  1332. nativeType += 6;
  1333. if (String::compare(nativeType, "char*") == 0 || String::compare(nativeType, "char *") == 0)
  1334. return "string";
  1335. else if (String::compare(nativeType, "S32") == 0)
  1336. return "int";
  1337. else if (String::compare(nativeType, "U32") == 0)
  1338. return "uint";
  1339. else if (String::compare(nativeType, "F32") == 0)
  1340. return "float";
  1341. const U32 length = dStrlen(nativeType);
  1342. if (nativeType[length - 1] == '&' || nativeType[length - 1] == '*')
  1343. return StringTable->insertn(nativeType, length - 1);
  1344. return nativeType;
  1345. }
  1346. }
  1347. String Namespace::Entry::getBriefDescription(String* outRemainingDocText) const
  1348. {
  1349. String docString = getDocString();
  1350. S32 newline = docString.find('\n');
  1351. if (newline == -1)
  1352. {
  1353. if (outRemainingDocText)
  1354. *outRemainingDocText = String();
  1355. return docString;
  1356. }
  1357. String brief = docString.substr(0, newline);
  1358. if (outRemainingDocText)
  1359. *outRemainingDocText = docString.substr(newline + 1);
  1360. return brief;
  1361. }
  1362. String Namespace::Entry::getDocString() const
  1363. {
  1364. const char* argListStart;
  1365. const char* argListEnd;
  1366. if (sFindArgumentListSubstring(mUsage, argListStart, argListEnd))
  1367. {
  1368. // Skip the " - " part present in some old doc strings.
  1369. const char* ptr = argListEnd;
  1370. while (*ptr && dIsspace(*ptr))
  1371. ptr++;
  1372. if (*ptr == '-')
  1373. {
  1374. ptr++;
  1375. while (*ptr && dIsspace(*ptr))
  1376. ptr++;
  1377. }
  1378. return ptr;
  1379. }
  1380. return mUsage;
  1381. }
  1382. String Namespace::Entry::getArgumentsString() const
  1383. {
  1384. StringBuilder str;
  1385. if (mHeader)
  1386. {
  1387. // Parse out the argument list string supplied with the extended
  1388. // function header and add default arguments as we go.
  1389. Vector< String > argList;
  1390. Vector< String > defaultArgList;
  1391. sParseList(mHeader->mArgString, argList);
  1392. sParseList(mHeader->mDefaultArgString, defaultArgList);
  1393. str.append('(');
  1394. const U32 numArgs = argList.size();
  1395. const U32 numDefaultArgs = defaultArgList.size();
  1396. const U32 firstDefaultArgIndex = numArgs - numDefaultArgs;
  1397. for (U32 i = 0; i < numArgs; ++i)
  1398. {
  1399. // Add separator if not first arg.
  1400. if (i > 0)
  1401. str.append(',');
  1402. // Add type and name.
  1403. String name;
  1404. String type;
  1405. sGetArgNameAndType(argList[i], type, name);
  1406. str.append(' ');
  1407. str.append(sGetDocTypeString(type));
  1408. str.append(' ');
  1409. str.append(name);
  1410. // Add default value, if any.
  1411. if (i >= firstDefaultArgIndex)
  1412. {
  1413. str.append('=');
  1414. str.append(defaultArgList[i - firstDefaultArgIndex]);
  1415. }
  1416. }
  1417. if (numArgs > 0)
  1418. str.append(' ');
  1419. str.append(')');
  1420. }
  1421. else
  1422. {
  1423. // No extended function header. Try to parse out the argument
  1424. // list from the usage string.
  1425. const char* argListStart;
  1426. const char* argListEnd;
  1427. if (sFindArgumentListSubstring(mUsage, argListStart, argListEnd))
  1428. str.append(argListStart, argListEnd - argListStart);
  1429. else if (mType == ConsoleFunctionType && mCode)
  1430. {
  1431. // This isn't correct but the nonsense console stuff is set up such that all
  1432. // functions that have no function bodies are keyed to offset 0 to indicate "no code."
  1433. // This loses the association with the original function definition so we can't really
  1434. // tell here what the actual prototype is except if we searched though the entire opcode
  1435. // stream for the corresponding OP_FUNC_DECL (which would require dealing with the
  1436. // variable-size instructions).
  1437. if (!mFunctionOffset)
  1438. return "()";
  1439. String args = mCode->getFunctionArgs(mFunctionOffset);
  1440. if (args.isEmpty())
  1441. return "()";
  1442. str.append("( ");
  1443. str.append(args);
  1444. str.append(" )");
  1445. }
  1446. }
  1447. return str.end();
  1448. }
  1449. String Namespace::Entry::getPrototypeString() const
  1450. {
  1451. StringBuilder str;
  1452. // Start with return type.
  1453. if (mHeader && mHeader->mReturnString)
  1454. {
  1455. str.append(sGetDocTypeString(mHeader->mReturnString));
  1456. str.append(' ');
  1457. }
  1458. else
  1459. switch (mType)
  1460. {
  1461. case StringCallbackType:
  1462. str.append("string ");
  1463. break;
  1464. case IntCallbackType:
  1465. str.append("int ");
  1466. break;
  1467. case FloatCallbackType:
  1468. str.append("float ");
  1469. break;
  1470. case VoidCallbackType:
  1471. str.append("void ");
  1472. break;
  1473. case BoolCallbackType:
  1474. str.append("bool ");
  1475. break;
  1476. case ScriptCallbackType:
  1477. break;
  1478. }
  1479. // Add function name and arguments.
  1480. if (mType == ScriptCallbackType)
  1481. str.append(cb.mCallbackName);
  1482. else
  1483. str.append(mFunctionName);
  1484. str.append(getArgumentsString());
  1485. return str.end();
  1486. }
  1487. //-----------------------------------------------------------------------------
  1488. StringTableEntry Namespace::mActivePackages[Namespace::MaxActivePackages];
  1489. U32 Namespace::mNumActivePackages = 0;
  1490. U32 Namespace::mOldNumActivePackages = 0;
  1491. bool Namespace::isPackage(StringTableEntry name)
  1492. {
  1493. for (Namespace *walk = mNamespaceList; walk; walk = walk->mNext)
  1494. if (walk->mPackage == name)
  1495. return true;
  1496. return false;
  1497. }
  1498. U32 Namespace::getActivePackagesCount()
  1499. {
  1500. return mNumActivePackages;
  1501. }
  1502. StringTableEntry Namespace::getActivePackage(U32 index)
  1503. {
  1504. if (index >= mNumActivePackages)
  1505. return StringTable->EmptyString();
  1506. return mActivePackages[index];
  1507. }
  1508. void Namespace::activatePackage(StringTableEntry name)
  1509. {
  1510. if (mNumActivePackages == MaxActivePackages)
  1511. {
  1512. Con::printf("ActivatePackage(%s) failed - Max package limit reached: %d", name, MaxActivePackages);
  1513. return;
  1514. }
  1515. if (!name)
  1516. return;
  1517. // see if this one's already active
  1518. for (U32 i = 0; i < mNumActivePackages; i++)
  1519. if (mActivePackages[i] == name)
  1520. return;
  1521. // kill the cache
  1522. trashCache();
  1523. // find all the package namespaces...
  1524. for (Namespace *walk = mNamespaceList; walk; walk = walk->mNext)
  1525. {
  1526. if (walk->mPackage == name)
  1527. {
  1528. Namespace *parent = Namespace::find(walk->mName);
  1529. // hook the parent
  1530. walk->mParent = parent->mParent;
  1531. parent->mParent = walk;
  1532. // now swap the entries:
  1533. Entry *ew;
  1534. for (ew = parent->mEntryList; ew; ew = ew->mNext)
  1535. ew->mNamespace = walk;
  1536. for (ew = walk->mEntryList; ew; ew = ew->mNext)
  1537. ew->mNamespace = parent;
  1538. ew = walk->mEntryList;
  1539. walk->mEntryList = parent->mEntryList;
  1540. parent->mEntryList = ew;
  1541. }
  1542. }
  1543. mActivePackages[mNumActivePackages++] = name;
  1544. }
  1545. void Namespace::deactivatePackage(StringTableEntry name)
  1546. {
  1547. U32 oldNumActivePackages = mNumActivePackages;
  1548. // Remove all packages down to the given one
  1549. deactivatePackageStack(name);
  1550. // Now add back all packages that followed the given one
  1551. if (!oldNumActivePackages)
  1552. return;
  1553. for (U32 i = mNumActivePackages + 1; i < oldNumActivePackages; i++)
  1554. activatePackage(mActivePackages[i]);
  1555. }
  1556. void Namespace::deactivatePackageStack(StringTableEntry name)
  1557. {
  1558. S32 i, j;
  1559. for (i = 0; i < mNumActivePackages; i++)
  1560. if (mActivePackages[i] == name)
  1561. break;
  1562. if (i == mNumActivePackages)
  1563. return;
  1564. trashCache();
  1565. // Remove all packages down to the given one
  1566. for (j = mNumActivePackages - 1; j >= i; j--)
  1567. {
  1568. // gotta unlink em in reverse order...
  1569. for (Namespace *walk = mNamespaceList; walk; walk = walk->mNext)
  1570. {
  1571. if (walk->mPackage == mActivePackages[j])
  1572. {
  1573. Namespace *parent = Namespace::find(walk->mName);
  1574. // hook the parent
  1575. parent->mParent = walk->mParent;
  1576. walk->mParent = NULL;
  1577. // now swap the entries:
  1578. Entry *ew;
  1579. for (ew = parent->mEntryList; ew; ew = ew->mNext)
  1580. ew->mNamespace = walk;
  1581. for (ew = walk->mEntryList; ew; ew = ew->mNext)
  1582. ew->mNamespace = parent;
  1583. ew = walk->mEntryList;
  1584. walk->mEntryList = parent->mEntryList;
  1585. parent->mEntryList = ew;
  1586. }
  1587. }
  1588. }
  1589. mNumActivePackages = i;
  1590. }
  1591. void Namespace::unlinkPackages()
  1592. {
  1593. mOldNumActivePackages = mNumActivePackages;
  1594. if (!mNumActivePackages)
  1595. return;
  1596. deactivatePackageStack(mActivePackages[0]);
  1597. }
  1598. void Namespace::relinkPackages()
  1599. {
  1600. if (!mOldNumActivePackages)
  1601. return;
  1602. for (U32 i = 0; i < mOldNumActivePackages; i++)
  1603. activatePackage(mActivePackages[i]);
  1604. }
  1605. DefineEngineFunction(isPackage, bool, (String identifier), ,
  1606. "@brief Returns true if the identifier is the name of a declared package.\n\n"
  1607. "@ingroup Packages\n")
  1608. {
  1609. StringTableEntry name = StringTable->insert(identifier.c_str());
  1610. return Namespace::isPackage(name);
  1611. }
  1612. DefineEngineFunction(activatePackage, void, (String packageName), ,
  1613. "@brief Activates an existing package.\n\n"
  1614. "The activation occurs by updating the namespace linkage of existing functions and methods. "
  1615. "If the package is already activated the function does nothing.\n"
  1616. "@ingroup Packages\n")
  1617. {
  1618. StringTableEntry name = StringTable->insert(packageName.c_str());
  1619. Namespace::activatePackage(name);
  1620. }
  1621. DefineEngineFunction(deactivatePackage, void, (String packageName), ,
  1622. "@brief Deactivates a previously activated package.\n\n"
  1623. "The package is deactivated by removing its namespace linkages to any function or method. "
  1624. "If there are any packages above this one in the stack they are deactivated as well. "
  1625. "If the package is not on the stack this function does nothing.\n"
  1626. "@ingroup Packages\n")
  1627. {
  1628. StringTableEntry name = StringTable->insert(packageName.c_str());
  1629. Namespace::deactivatePackage(name);
  1630. }
  1631. DefineEngineFunction(getPackageList, const char*, (), ,
  1632. "@brief Returns a space delimited list of the active packages in stack order.\n\n"
  1633. "@ingroup Packages\n")
  1634. {
  1635. if (Namespace::getActivePackagesCount() == 0)
  1636. return "";
  1637. // Determine size of return buffer
  1638. dsize_t buffersize = 0;
  1639. for (U32 i = 0; i < Namespace::getActivePackagesCount(); ++i)
  1640. {
  1641. buffersize += dStrlen(Namespace::getActivePackage(i)) + 1;
  1642. }
  1643. U32 maxBufferSize = buffersize + 1;
  1644. char* returnBuffer = Con::getReturnBuffer(maxBufferSize);
  1645. U32 returnLen = 0;
  1646. for (U32 i = 0; i < Namespace::getActivePackagesCount(); ++i)
  1647. {
  1648. dSprintf(returnBuffer + returnLen, maxBufferSize - returnLen, "%s ", Namespace::getActivePackage(i));
  1649. returnLen = dStrlen(returnBuffer);
  1650. }
  1651. // Trim off the last extra space
  1652. if (returnLen > 0 && returnBuffer[returnLen - 1] == ' ')
  1653. returnBuffer[returnLen - 1] = '\0';
  1654. return returnBuffer;
  1655. }