void XMLExport::exportNamespaces() { // keep track of which enumTables are in use Vector < const EnumTable*> enumTables; mXML->pushNewElement("Namespaces"); for (Namespace *walk = Namespace::mNamespaceList; walk; walk = walk->mNext) { if ( walk->mName && !walk->isClass() ) continue; const char *name = walk->mName ? walk->mName : ""; mXML->pushNewElement("Namespace"); mXML->setAttribute("name", name); Namespace *p = walk->mParent; mXML->pushNewElement("Parents"); while (p) { if (p->mName == walk->mName) { p = p->mParent; continue; } const char* pname = p->mName ? p->mName : ""; mXML->pushNewElement("Parent"); mXML->setAttribute("name", pname); mXML->popElement(); // Parent p = p->mParent; } mXML->popElement(); // Parents // Entries (Engine/Script Methods/Functions) mXML->pushNewElement("Entries"); Namespace::Entry *entry; VectorPtr<Namespace::Entry *> vec; walk->getEntryList(&vec); for( NamespaceEntryListIterator compItr = vec.begin(); compItr != vec.end(); compItr++ ) { entry = *compItr; if (entry->mNamespace != walk) continue; if (entry->mNamespace->mName != walk->mName) continue; mXML->pushNewElement("Entry"); //consistently name functions char functionName[512]; dSprintf(functionName, 512, entry->mFunctionName); functionName[0] = dTolower(functionName[0]); S32 minArgs = entry->mMinArgs; S32 maxArgs = entry->mMaxArgs; if (maxArgs < minArgs) maxArgs = minArgs; mXML->setAttribute("name", functionName); mXML->setAttribute("minArgs", avar("%i", minArgs)); mXML->setAttribute("maxArgs", avar("%i", maxArgs)); const char* usage = ""; if (entry->mUsage && entry->mUsage[0]) usage = entry->mUsage; mXML->setAttribute("usage", usage); mXML->setAttribute("package", entry->mPackage ? entry->mPackage : ""); mXML->setAttribute("entryType", avar("%i", entry->mType)); mXML->popElement(); // Entry } mXML->popElement(); // Entries // Fields mXML->pushNewElement("Fields"); AbstractClassRep *rep = walk->mClassRep; Vector<U32> classFields; if (rep) { AbstractClassRep *parentRep = rep->getParentClass(); const AbstractClassRep::FieldList& flist = rep->mFieldList; for(U32 i = 0; i < flist.size(); i++) { if (parentRep) { if (parentRep->findField(flist[i].pFieldname)) continue; } classFields.push_back(i); } for(U32 i = 0; i < classFields.size(); i++) { U32 index = classFields[i]; char fieldName[256]; dSprintf(fieldName, 256, flist[index].pFieldname); //consistently name fields fieldName[0] = dToupper(fieldName[0]); mXML->pushNewElement("Field"); mXML->setAttribute("name", fieldName); mXML->setAttribute("type", avar("%i", flist[index].type)); // RD: temporarily deactivated; TypeEnum is no more; need to sync this up // if (flist[index].type == TypeEnum && flist[index].table && dStrlen(flist[index].table->name)) // { // if (!enumTables.contains(flist[index].table)) // enumTables.push_back(flist[index].table); // // mXML->setAttribute("enumTable", flist[index].table->name); // // } const char* pFieldDocs = ""; if (flist[index].pFieldDocs && flist[index].pFieldDocs[0]) pFieldDocs = flist[index].pFieldDocs; mXML->setAttribute("docs", pFieldDocs); mXML->setAttribute("elementCount", avar("%i", flist[index].elementCount)); mXML->popElement(); // Field } } mXML->popElement(); // Fields mXML->popElement(); // Namespace } mXML->popElement(); // Namespaces mXML->pushNewElement("EnumTables"); // write out the used EnumTables for (S32 i = 0; i < enumTables.size(); i++) { mXML->pushNewElement("EnumTable"); const EnumTable* table = enumTables[i]; mXML->setAttribute("name", table->name); mXML->setAttribute("firstFlag", avar("%i", table->firstFlag)); mXML->setAttribute("mask", avar("%i", table->mask)); mXML->pushNewElement("Enums"); for (S32 j = 0; j < table->size; j++) { mXML->pushNewElement("Enum"); mXML->setAttribute("name", table->table[j].label); mXML->setAttribute("index", avar("%i", table->table[j].index)); mXML->popElement(); // Enum } mXML->popElement(); //Enums mXML->popElement(); // EnumTable } mXML->popElement(); // EnumTables }
static void dumpClasses( Stream &stream ) { Namespace::trashCache(); VectorPtr<Namespace*> vec; vec.reserve( 1024 ); // We use mHashSequence to mark if we have traversed... // so mark all as zero to start. for ( Namespace *walk = Namespace::mNamespaceList; walk; walk = walk->mNext ) walk->mHashSequence = 0; for(Namespace *walk = Namespace::mNamespaceList; walk; walk = walk->mNext) { VectorPtr<Namespace*> stack; stack.reserve( 1024 ); // Get all the parents of this namespace... (and mark them as we go) Namespace *parentWalk = walk; while(parentWalk) { if(parentWalk->mHashSequence != 0) break; if(parentWalk->mPackage == 0) { parentWalk->mHashSequence = 1; // Mark as traversed. stack.push_back(parentWalk); } parentWalk = parentWalk->mParent; } // Load stack into our results vector. while(stack.size()) { vec.push_back(stack[stack.size() - 1]); stack.pop_back(); } } // Go through previously discovered classes U32 i; for(i = 0; i < vec.size(); i++) { const char *className = vec[i]->mName; const char *superClassName = vec[i]->mParent ? vec[i]->mParent->mName : NULL; // Skip the global namespace, that gets dealt with in dumpFunctions if(!className) continue; // We're just dumping engine functions, then we don't want to dump // a class that only contains script functions. So, we iterate over // all the functions. bool found = false; for( Namespace::Entry *ewalk = vec[i]->mEntryList; ewalk; ewalk = ewalk->mNext ) { if( ewalk->mType != Namespace::Entry::ConsoleFunctionType ) { found = true; break; } } // If we don't have engine functions and the namespace name // doesn't match the class name... then its a script class. if ( !found && !vec[i]->isClass() ) continue; // If we hit a class with no members and no classRep, do clever filtering. if(vec[i]->mEntryList == NULL && vec[i]->mClassRep == NULL) { // Print out a short stub so we get a proper class hierarchy. if ( superClassName ) { // Filter hack; we don't want non-inheriting classes... dumpClassHeader( stream, NULL, className, superClassName ); dumpClassFooter( stream ); } continue; } // Skip over hidden or internal classes. if( vec[i]->mUsage && ( dStrstr( vec[i]->mUsage, "@hide" ) || dStrstr( vec[i]->mUsage, "@internal" ) ) ) continue; // Print the header for the class.. dumpClassHeader( stream, vec[i]->mUsage, className, superClassName ); // Dump all fragments for this class. for( ConsoleDocFragment* fragment = ConsoleDocFragment::smFirst; fragment != NULL; fragment = fragment->mNext ) if( fragment->mClass && dStricmp( fragment->mClass, className ) == 0 ) dumpFragment( stream, fragment ); // Dump member functions. dumpNamespaceEntries( stream, vec[ i ], false ); // Dump callbacks. dumpGroupStart( stream, "Callbacks" ); dumpNamespaceEntries( stream, vec[ i ], true ); dumpGroupEnd( stream ); // Dump static member variables. dumpVariables( stream, className ); // Deal with the classRep (to get members)... AbstractClassRep *rep = vec[i]->mClassRep; AbstractClassRep::FieldList emptyList; AbstractClassRep::FieldList *parentList = &emptyList; AbstractClassRep::FieldList *fieldList = &emptyList; if ( rep ) { // Get information about the parent's fields... AbstractClassRep *parentRep = vec[i]->mParent ? vec[i]->mParent->mClassRep : NULL; if(parentRep) parentList = &(parentRep->mFieldList); // Get information about our fields fieldList = &(rep->mFieldList); // Go through all our fields... for(U32 j = 0; j < fieldList->size(); j++) { const AbstractClassRep::Field &field = (*fieldList)[j]; switch( field.type ) { case AbstractClassRep::StartArrayFieldType: case AbstractClassRep::EndArrayFieldType: break; case AbstractClassRep::StartGroupFieldType: dumpGroupStart( stream, field.pGroupname, field.pFieldDocs ); break; case AbstractClassRep::EndGroupFieldType: dumpGroupEnd( stream ); break; default: case AbstractClassRep::DeprecatedFieldType: // Skip over fields that are already defined in // our parent class. if ( parentRep && parentRep->findField( field.pFieldname ) ) continue; dumpClassMember( stream, field ); break; } } } // Close the class/namespace. dumpClassFooter( stream ); } }