2
0

consoleInternal.cpp 46 KB

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