consoleDoc.cpp
Engine/source/console/consoleDoc.cpp
For specifics on using the consoleDoc functionality, see console_autodoc.
Public Functions
ConsoleFunctionGroupBegin(ConsoleDoc , "Console self-documentation functions. These output psuedo C++ suitable <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> feeeding through Doxygen or another auto documentation tool." )
DefineEngineFunction(dumpConsoleClasses , void , (bool dumpScript, bool dumpEngine) , (true, true) , "@brief Dumps all declared console classes <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">console.\n\n</a>" "@param dumpScript Optional parameter specifying whether or not classes defined in script should be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">dumped.\n</a>" "@param dumpEngine Optional parameter specifying whether or not classes defined in the engine should be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">dumped.\n</a>" "@ingroup Logging" )
DefineEngineFunction(dumpConsoleFunctions , void , (bool dumpScript, bool dumpEngine) , (true, true) , "@brief Dumps all declared console functions <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">console.\n</a>" "@param dumpScript Optional parameter specifying whether or not functions defined in script should be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">dumped.\n</a>" "@param dumpEngine Optional parameter specitying whether or not functions defined in the engine should be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">dumped.\n</a>" "@ingroup Logging" )
printClassHeader(const char * usage, const char * className, const char * superClassName, const bool stub)
printGroupStart(const char * aName, const char * aDocs)
Detailed Description
For specifics on using the consoleDoc functionality, see console_autodoc.
Public Variables
const char * typeNames []
Helper table to convert type ids to human readable names.
Public Functions
ConsoleFunctionGroupBegin(ConsoleDoc , "Console self-documentation functions. These output psuedo C++ suitable <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> feeeding through Doxygen or another auto documentation tool." )
ConsoleFunctionGroupEnd(ConsoleDoc )
DefineEngineFunction(dumpConsoleClasses , void , (bool dumpScript, bool dumpEngine) , (true, true) , "@brief Dumps all declared console classes <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">console.\n\n</a>" "@param dumpScript Optional parameter specifying whether or not classes defined in script should be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">dumped.\n</a>" "@param dumpEngine Optional parameter specifying whether or not classes defined in the engine should be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">dumped.\n</a>" "@ingroup Logging" )
DefineEngineFunction(dumpConsoleFunctions , void , (bool dumpScript, bool dumpEngine) , (true, true) , "@brief Dumps all declared console functions <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">console.\n</a>" "@param dumpScript Optional parameter specifying whether or not functions defined in script should be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">dumped.\n</a>" "@param dumpEngine Optional parameter specitying whether or not functions defined in the engine should be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">dumped.\n</a>" "@ingroup Logging" )
printClassFooter()
printClassHeader(const char * usage, const char * className, const char * superClassName, const bool stub)
printClassMember(const bool isDeprec, const char * aType, const char * aName, const char * aDocs, S32 aElementCount)
printClassMethod(const bool isVirtual, const char * retType, const char * methodName, const char * args, const char * usage)
printGroupEnd()
printGroupStart(const char * aName, const char * aDocs)
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "console/console.h" 26 27#include "console/ast.h" 28#include "core/tAlgorithm.h" 29 30#include "core/strings/findMatch.h" 31#include "console/consoleInternal.h" 32#include "console/consoleObject.h" 33#include "core/stream/fileStream.h" 34#include "console/compiler.h" 35#include "core/frameAllocator.h" 36#include "console/engineAPI.h" 37 38//--- Information pertaining to this page... ------------------ 39/// @file 40/// 41/// For specifics on using the consoleDoc functionality, see @ref console_autodoc 42 43ConsoleFunctionGroupBegin(ConsoleDoc, "Console self-documentation functions. These output psuedo C++ suitable for feeeding through Doxygen or another auto documentation tool."); 44 45DefineEngineFunction( dumpConsoleClasses, void, (bool dumpScript, bool dumpEngine), ( true, true ), 46 "@brief Dumps all declared console classes to the console.\n\n" 47 "@param dumpScript Optional parameter specifying whether or not classes defined in script should be dumped.\n" 48 "@param dumpEngine Optional parameter specifying whether or not classes defined in the engine should be dumped.\n" 49 "@ingroup Logging") 50{ 51 Namespace::dumpClasses( dumpScript, dumpEngine ); 52} 53 54DefineEngineFunction(dumpConsoleFunctions, void, ( bool dumpScript, bool dumpEngine ), ( true, true ), 55 "@brief Dumps all declared console functions to the console.\n" 56 "@param dumpScript Optional parameter specifying whether or not functions defined in script should be dumped.\n" 57 "@param dumpEngine Optional parameter specitying whether or not functions defined in the engine should be dumped.\n" 58 "@ingroup Logging") 59{ 60 Namespace::dumpFunctions( dumpScript, dumpEngine ); 61} 62 63ConsoleFunctionGroupEnd(ConsoleDoc); 64 65/// Helper table to convert type ids to human readable names. 66const char *typeNames[] = 67{ 68 "Script", 69 "string", 70 "int", 71 "float", 72 "void", 73 "bool", 74 "", 75 "", 76 "unknown_overload" 77}; 78 79void printClassHeader(const char* usage, const char * className, const char * superClassName, const bool stub) 80{ 81 if(stub) 82 { 83 Con::printf("/// Stub class"); 84 Con::printf("/// "); 85 Con::printf("/// @note This is a stub class to ensure a proper class hierarchy. No "); 86 Con::printf("/// information was available for this class."); 87 } 88 89 if((usage != NULL) && strlen(usage)) 90 { 91 // Copy Usage Document 92 S32 usageLen = dStrlen( usage ) + 1; 93 FrameTemp<char> usageStr( usageLen ); 94 dStrcpy( usageStr, usage, usageLen ); 95 96 // Print Header 97 Con::printf( "/*!" ); 98 99 // Print line by line, skipping the @field lines. 100 // 101 // fetch first line end 102 char *newLine = dStrchr( usageStr, '\n' ); 103 char *usagePtr = usageStr; 104 do 105 { 106 // Copy of one line 107 static char lineStr[2048] = {0}; 108 // Keyword will hold the last keyword (word following '@' or '\') encountered. 109 static char keyword[8] = {0}; 110 111 S32 lineLen = 0; 112 113 // If not the last line, increment pointer 114 if( newLine != NULL ) 115 { 116 *newLine = '\0'; 117 newLine ++; 118 } 119 120 // Copy line and update usagePtr 121 dStrcpy( lineStr, usagePtr, 2048 ); 122 usagePtr = (newLine != NULL ) ? newLine : usagePtr; 123 lineLen = dStrlen( lineStr ); 124 125 // Get the keyword. This is the first word after an '@' or '\'. 126 const char* tempkw = dStrchr( lineStr, '@' ); 127 if( !tempkw ) 128 tempkw = dStrchr( lineStr, '\\' ); 129 130 // If we found a new keyword, set it, otherwise, keep using the 131 // most recently found. 132 if( tempkw ) 133 { 134 dStrncpy( keyword, tempkw + 1, 5 ); 135 keyword[5] = '\0'; 136 } 137 138 // Print all fields that aren't associated with the 'field' keyword. 139 if( String::compare( keyword, "field" ) ) 140 Con::printf( "%s", lineStr ); // print lineStr as an unformatted string (otherwise '%' characters in the string could cause problems) 141 142 143 // Fetch next line ending 144 newLine = dStrchr( usagePtr, '\n' ); 145 } while( newLine != NULL ); 146 147 // DocBlock Footer 148 Con::printf( " */" ); 149 150 } 151 152 // Print out appropriate class header 153 if(superClassName) 154 Con::printf("class %s : public %s {", className, superClassName ? superClassName : ""); 155 else if(!className) 156 Con::printf("namespace Global {"); 157 else 158 Con::printf("class %s {", className); 159 160 if(className) 161 Con::printf(" public:"); 162 163} 164 165void printClassMethod(const bool isVirtual, const char *retType, const char *methodName, const char* args, const char*usage) 166{ 167 if(usage && usage[0] != ';' && usage[0] != 0) 168 Con::printf(" /*! %s */", usage); 169 Con::printf(" %s%s %s(%s) {}", isVirtual ? "virtual " : "", retType, methodName, args); 170} 171 172void printGroupStart(const char * aName, const char * aDocs) 173{ 174 Con::printf(""); 175 Con::printf(" /*! @name %s", aName); 176 177 if(aDocs) 178 { 179 Con::printf(" "); 180 Con::printf(" %s", aDocs); 181 } 182 183 Con::printf(" @{ */"); 184 185 // Add a blank comment in order to make sure groups are parsed properly. 186 Con::printf(" /*! */"); 187} 188 189void printClassMember(const bool isDeprec, const char * aType, const char * aName, const char * aDocs, S32 aElementCount) 190{ 191 Con::printf(" /*!"); 192 193 if(aDocs) 194 { 195 Con::printf(" %s", aDocs); 196 Con::printf(" "); 197 } 198 199 if(isDeprec) 200 Con::printf(" @deprecated This member is deprecated, which means that its value is always undefined."); 201 202 Con::printf(" */"); 203 204 if (aElementCount == 1) 205 { 206 Con::printf(" %s %s;", isDeprec ? "deprecated" : aType, aName); 207 } 208 else 209 { 210 Con::printf(" %s %s[%i];", isDeprec ? "deprecated" : aType, aName, aElementCount); 211 } 212} 213 214void printGroupEnd() 215{ 216 Con::printf(" /// @}"); 217 Con::printf(""); 218} 219 220void printClassFooter() 221{ 222 Con::printf("};"); 223 Con::printf(""); 224} 225 226void Namespace::printNamespaceEntries(Namespace * g, bool dumpScript, bool dumpEngine ) 227{ 228 static bool inGroup = false; 229 230 // Go through all the entries. 231 // Iterate through the methods of the namespace... 232 for(Entry *ewalk = g->mEntryList; ewalk; ewalk = ewalk->mNext) 233 { 234 S32 eType = ewalk->mType; 235 const char * funcName = ewalk->mFunctionName; 236 237 if( ( eType == Entry::ConsoleFunctionType ) && !dumpScript ) 238 continue; 239 240 if( ( eType != Entry::ConsoleFunctionType ) && !dumpEngine ) 241 continue; 242 243 // If it's a function 244 if( eType >= Entry::ConsoleFunctionType ) 245 { 246 if (ewalk->mHeader != NULL) 247 { 248 // The function was defined with types, so we can print out the actual return type 249 printClassMethod(true, ewalk->mHeader->mReturnString, funcName, ewalk->getArgumentsString().c_str(), 250 ewalk->getDocString().c_str()); 251 } 252 else 253 { 254 printClassMethod(true, typeNames[eType], funcName, (ewalk->getArgumentsString() + "...").c_str(), 255 ewalk->getDocString().c_str()); 256 } 257 } 258 else if(ewalk->mType == Entry::GroupMarker) 259 { 260 if(!inGroup) 261 printGroupStart(ewalk->cb.mGroupName, ewalk->mUsage); 262 else 263 printGroupEnd(); 264 265 inGroup = !inGroup; 266 } 267 else if(ewalk->mType == Entry::ScriptCallbackType) 268 { 269 // It's a script callback - emit some sort of appropriate info. 270 Con::printf(" /*! %s */", ewalk->getDocString().c_str()); 271 Con::printf(" %s;", ewalk->getPrototypeString().c_str()); 272 Con::printf(""); 273 } 274 else if(ewalk->mFunctionOffset) // If it's a builtin function... 275 { 276 String args = ewalk->mCode->getFunctionArgs(ewalk->mFunctionOffset); 277 printClassMethod(false, typeNames[ewalk->mType], ewalk->mFunctionName, args, ""); 278 } 279 else 280 { 281 Con::printf(" // got an unknown thing?? %d", ewalk->mType ); 282 } 283 } 284} 285 286void Namespace::dumpClasses( bool dumpScript, bool dumpEngine ) 287{ 288 VectorPtr<Namespace*> vec; 289 trashCache(); 290 vec.reserve( 1024 ); 291 292 // We use mHashSequence to mark if we have traversed... 293 // so mark all as zero to start. 294 for(Namespace *walk = mNamespaceList; walk; walk = walk->mNext) 295 walk->mHashSequence = 0; 296 297 for(Namespace *walk = mNamespaceList; walk; walk = walk->mNext) 298 { 299 VectorPtr<Namespace*> stack; 300 stack.reserve( 1024 ); 301 302 // Get all the parents of this namespace... (and mark them as we go) 303 Namespace *parentWalk = walk; 304 while(parentWalk) 305 { 306 if(parentWalk->mHashSequence != 0) 307 break; 308 if(parentWalk->mPackage == 0) 309 { 310 parentWalk->mHashSequence = 1; // Mark as traversed. 311 stack.push_back(parentWalk); 312 } 313 parentWalk = parentWalk->mParent; 314 } 315 316 // Load stack into our results vector. 317 while(stack.size()) 318 { 319 vec.push_back(stack[stack.size() - 1]); 320 stack.pop_back(); 321 } 322 } 323 324 // Go through previously discovered classes 325 U32 i; 326 for(i = 0; i < vec.size(); i++) 327 { 328 const char *className = vec[i]->mName; 329 const char *superClassName = vec[i]->mParent ? vec[i]->mParent->mName : NULL; 330 331 // Skip the global namespace, that gets dealt with in dumpFunctions 332 if(!className) continue; 333 334 // If we're just dumping script functions, then we don't want to dump 335 // a class that only contains script functions. So, we iterate over all 336 // the functions. 337 if( !dumpScript ) 338 { 339 bool found = false; 340 for(Entry *ewalk = vec[i]->mEntryList; ewalk; ewalk = ewalk->mNext) 341 { 342 if( ewalk->mType != Entry::ConsoleFunctionType ) 343 { 344 found = true; 345 break; 346 } 347 } 348 349 // If we don't have engine functions and the namespace name 350 // doesn't match the class name... then its a script class. 351 if ( !found && !vec[i]->isClass() ) 352 continue; 353 } 354 355 // And we do the same for engine functions. 356 if( !dumpEngine ) 357 { 358 bool found = false; 359 for(Entry *ewalk = vec[i]->mEntryList; ewalk; ewalk = ewalk->mNext) 360 { 361 if( ewalk->mType == Entry::ConsoleFunctionType ) 362 { 363 found = true; 364 break; 365 } 366 } 367 if( !found ) 368 continue; 369 } 370 371 // If we hit a class with no members and no classRep, do clever filtering. 372 if(vec[i]->mEntryList == NULL && vec[i]->mClassRep == NULL) 373 { 374 // Print out a short stub so we get a proper class hierarchy. 375 if(superClassName) { // Filter hack; we don't want non-inheriting classes... 376 printClassHeader( NULL, className,superClassName, true); 377 printClassFooter(); 378 } 379 continue; 380 } 381 382 // Print the header for the class.. 383 printClassHeader(vec[i]->mUsage, className, superClassName, false); 384 385 // Deal with entries. 386 printNamespaceEntries(vec[i], dumpScript, dumpEngine); 387 388 // Deal with the classRep (to get members)... 389 AbstractClassRep *rep = vec[i]->mClassRep; 390 AbstractClassRep::FieldList emptyList; 391 AbstractClassRep::FieldList *parentList = &emptyList; 392 AbstractClassRep::FieldList *fieldList = &emptyList; 393 394 // Since all fields are defined in the engine, if we're not dumping 395 // engine stuff, than we shouldn't dump the fields. 396 if(dumpEngine && rep) 397 { 398 // Get information about the parent's fields... 399 AbstractClassRep *parentRep = vec[i]->mParent ? vec[i]->mParent->mClassRep : NULL; 400 if(parentRep) 401 parentList = &(parentRep->mFieldList); 402 403 // Get information about our fields 404 fieldList = &(rep->mFieldList); 405 406 // Go through all our fields... 407 for(U32 j = 0; j < fieldList->size(); j++) 408 { 409 switch((*fieldList)[j].type) 410 { 411 case AbstractClassRep::StartArrayFieldType: 412 case AbstractClassRep::EndArrayFieldType: 413 break; 414 case AbstractClassRep::StartGroupFieldType: 415 printGroupStart((*fieldList)[j].pGroupname, (*fieldList)[j].pFieldDocs); 416 break; 417 case AbstractClassRep::EndGroupFieldType: 418 printGroupEnd(); 419 break; 420 default: 421 case AbstractClassRep::DeprecatedFieldType: 422 { 423 // Skip over fields that are already defined in 424 // our parent class. 425 if ( parentRep && parentRep->findField( (*fieldList)[j].pFieldname ) ) 426 continue; 427 428 bool isDeprecated = ((*fieldList)[j].type == AbstractClassRep::DeprecatedFieldType); 429 430 if(isDeprecated) 431 { 432 printClassMember( 433 true, 434 "<deprecated>", 435 (*fieldList)[j].pFieldname, 436 (*fieldList)[j].pFieldDocs, 437 (*fieldList)[j].elementCount 438 ); 439 } 440 else 441 { 442 ConsoleBaseType *cbt = ConsoleBaseType::getType((*fieldList)[j].type); 443 444 printClassMember( 445 false, 446 cbt ? cbt->getTypeClassName() : "<unknown>", 447 (*fieldList)[j].pFieldname, 448 (*fieldList)[j].pFieldDocs, 449 (*fieldList)[j].elementCount 450 ); 451 } 452 } 453 } 454 } 455 } 456 457 if( dumpScript ) 458 { 459 // Print out fields defined in script docs for this namespace. 460 // These fields are specified by the 'field' keyword in the usage 461 // string. 462 463 // The field type and name. 464 char fieldName[256]; 465 char fieldDoc[1024]; 466 467 // Usage string iterator. 468 const char* field = vec[i]->mUsage; 469 470 while( field ) 471 { 472 // Find the first field keyword. 473 const char* tempField = dStrstr( field, "@field" ); 474 if( !tempField ) 475 tempField = dStrstr( field, "\\field" ); 476 477 field = tempField; 478 479 if( !field ) 480 break; 481 482 // Move to the field name. 483 field += 7; 484 485 // Copy the field type and name. These should both be followed by a 486 // space so only in this case will we actually store it. 487 S32 spaceCount = 0; 488 S32 index = 0; 489 bool valid = false; 490 while( field && ( *field != '\n' ) ) 491 { 492 if( index >= 255 ) 493 break; 494 495 if( *field == ' ' ) 496 spaceCount++; 497 498 if( spaceCount == 2 ) 499 { 500 valid = true; 501 break; 502 } 503 504 fieldName[index++] = *field; 505 field++; 506 } 507 508 if( !valid ) 509 continue; 510 511 fieldName[index] = '\0'; 512 513 // Now copy from field to the next keyword. 514 const char* nextKeyword = dStrchr( field, '@' ); 515 if( !nextKeyword ) 516 nextKeyword = dStrchr( field, '\\' ); 517 518 // Grab the length of the doc string. 519 S32 docLen = dStrlen( field ); 520 if( nextKeyword ) 521 docLen = nextKeyword - field; 522 523 // Make sure it will fit in the buffer. 524 if( docLen > 1023 ) 525 docLen = 1023; 526 527 // Copy. 528 dStrncpy( fieldDoc, field, docLen ); 529 fieldDoc[docLen] = '\0'; 530 field += docLen; 531 532 // Print 533 Con::printf( " /*!" ); 534 Con::printf( " %s", fieldDoc ); 535 Con::printf( " */" ); 536 Con::printf( " %s;", fieldName ); 537 } 538 } 539 540 // Close the class/namespace. 541 printClassFooter(); 542 } 543} 544 545void Namespace::dumpFunctions( bool dumpScript, bool dumpEngine ) 546{ 547 // Get the global namespace. 548 Namespace* g = find(NULL); //->mParent; 549 550 printClassHeader(NULL, NULL,NULL, false); 551 552 while(g) 553 { 554 printNamespaceEntries(g, dumpScript, dumpEngine ); 555 g = g->mParent; 556 } 557 558 printClassFooter(); 559} 560