static String reduceLinkerToken(const String& token) { static const char* const _prefixes[] = { "-weak", "-reexport", "-lazy", "-upward" }; static StringVec prefixes(_prefixes, _prefixes + sizeof(_prefixes) / sizeof(char*)); StringVec::const_iterator pIt = prefixes.begin(); for (; pIt != prefixes.end(); ++pIt) { size_t prefixLen = pIt->length(); if (token.length() > prefixLen && strBeginsWith(token, *pIt) && (token[prefixLen] == '_' || token[prefixLen] == '-')) return "-" + token.substr(prefixLen + 1); } return token; }
void ProcessArea( __in const NWN::ResRef32 & AreaResRef, __in ResourceManager & ResMan, __in IDebugTextOut * TextOut, __in unsigned long ObjectTypeMask, __in const StringVec & TemplateNames, __in const StringVec & ExcludeFields, __in const StringVec & IncludeFields ) /*++ Routine Description: This routine updates placed instances within a given area with data from their templates. Arguments: AreaResRef - Supplies the resource name of the area to display. ResMan - Supplies a reference to the resource manager instance to use in order to load any associated resource data. TextOut - Supplies the text output interface. ObjectTypeMask - Supplies the mask of object types to update templates for. TemplateNames - Supplies the RESREF names of templates that are to be updated. ExcludeFields - Supplies a list of fields that are to be excluded from copying even if they are present in the template. Return Value: None. An std::exception is raised on failure. Environment: User mode. --*/ { // // Areas are comprised of two files, an <area>.are with area parameters, // and an <area>.git with the object instance parameters about objects that // have been placed in the area via the toolset. // DemandResource32 AreFile( ResMan, AreaResRef, NWN::ResARE ); DemandResource32 GitFile( ResMan, AreaResRef, NWN::ResGIT ); GffFileReader Are( AreFile, ResMan ); GffFileReader::Ptr Git = new GffFileReader( GitFile, ResMan ); GffFileWriter GitWriter; const GffFileReader::GffStruct * RootStruct; GffFileWriter::GffStruct GitWriterRoot; std::string AreaName; std::string AreaTag; // // Start off by duplicating the current GIT contents over to the new output // GIT. // RootStruct = Are.GetRootStruct( ); GitWriter.InitializeFromReader( Git.get( ) ); // // Acquire parameters we need from area.git. // if (!RootStruct->GetCExoLocString( "Name", AreaName )) throw std::runtime_error( "Failed to read area Name" ); if (!RootStruct->GetCExoString( "Tag", AreaTag )) throw std::runtime_error( "Failed to read area Tag" ); TextOut->WriteText( "Updating instance information for area %s (tag %s)...\n", AreaName.c_str( ), AreaTag.c_str( )); // // Now update each of the instance data items that we are interested in. // RootStruct = Git->GetRootStruct( ); GitWriterRoot = GitWriter.GetRootStruct( ); for (size_t i = 0; i < NumValidObjectTypes; i += 1) { if (ObjectTypeMask > 0 && !(ObjectTypeMask & (1 << ValidObjectTypes[ i ].TypeCode ))) continue; // // This is an object type we're interested in, scan for objects that have // a template we're to refresh and copy the data. // for (size_t j = 0; j <= ULONG_MAX; j += 1) { GffFileReader::GffStruct ObjStructIn; GffFileWriter::GffStruct ObjStructOut; NWN::ResRef32 TemplateResRef; std::string TemplateString; bool MatchingTemplate; std::string FileName; GffFileReader::Ptr TemplateReader; // // Fetch the corresponding list element in both the input and output // GITs so that we can make modifications as necessary. // if (!RootStruct->GetListElement( ValidObjectTypes[ i ].InstanceListName, j, ObjStructIn )) break; if (!GitWriterRoot.GetListElement( ValidObjectTypes[ i ].InstanceListName, j, ObjStructOut )) throw std::runtime_error( "Internal error: GFF reader/writer out of sync." ); // // If the object instance had no associated template, there's nothing // for us to update, so skip it. // if (!ObjStructIn.GetResRef( "TemplateResRef", TemplateResRef )) continue; TemplateString = ResMan.StrFromResRef( TemplateResRef ); MatchingTemplate = TemplateNames.empty(); // if empty then ignore filter for (StringVec::const_iterator it = TemplateNames.begin( ); it != TemplateNames.end( ); ++it) { if (!_stricmp( it->c_str( ), TemplateString.c_str( ) )) { MatchingTemplate = true; break; } } if (!MatchingTemplate) continue; // // This instance appears to be one that we should update, try and // process it. // TextOut->WriteText( "Refreshing template data for object #%lu of type %s (template %s.%s)...\n", (unsigned long) j, ValidObjectTypes[ i ].TypeName, TemplateString.c_str( ), ResMan.ResTypeToExt( ValidObjectTypes[ i ].TemplateResType )); // // Note that we must be careful here, as not only may objects have bad // template RESREFs, they may also have RESREFs to files that are not // even legal GFF-based templates to begin with! (e.g. fireplace.upe). // try { FileName = ResMan.Demand( TemplateResRef, ValidObjectTypes[ i ].TemplateResType); } catch (std::exception &e) { TextOut->WriteText( "WARNING: Exception '%s' locating template %s.%s, skipping object instance...\n", e.what( ), TemplateString.c_str( ), ResMan.ResTypeToExt( ValidObjectTypes[ i ].TemplateResType )); continue; } try { TemplateReader = new GffFileReader( FileName, ResMan); } catch (std::exception &e) { TextOut->WriteText( "WARNING: Exception '%s' loading template %s.%s, skipping object instance...\n", e.what( ), TemplateString.c_str( ), ResMan.ResTypeToExt( ValidObjectTypes[ i ].TemplateResType )); ResMan.Release( FileName ); continue; } // // Finally, update the instance data. // try { UpdateObjectInstanceFromTemplate( TemplateReader->GetRootStruct( ), &ObjStructIn, &ObjStructOut, ExcludeFields, IncludeFields, TextOut); } catch (std::exception &e) { TextOut->WriteText( "WARNING: Exception '%s' refreshing object instance from template %s.%s, skipping object instance...\n", e.what( ), TemplateString.c_str( ), ResMan.ResTypeToExt( ValidObjectTypes[ i ].TemplateResType )); } TemplateReader = NULL; ResMan.Release( FileName ); } } // // Now replace the object instance GFF with our edited version. // Git = NULL; GitWriter.Commit( GitFile, GffFileWriter::GIT_FILE_TYPE, GffFileWriter::GFF_COMMIT_FLAG_SEQUENTIAL); }
/*static*/ bool StructureParser::matchLine (char finishing) { // Case 1. Namespace definition if (mIncomingLine.size() == 2 && mIncomingLine[0] == "namespace" && finishing == '{'){ NamespaceElement * element = new NamespaceElement(); element->name = mIncomingLine[1]; push (element); return true; } // Case 2. Enum definition if (mIncomingLine.size() == 2 && mIncomingLine[0] == "enum" && finishing == '{'){ EnumElement * element = new EnumElement; element->name = mIncomingLine[1]; push (element); return true; } // Case 3. Simple Structure/Class Definition if (mIncomingLine.size() == 2 && (mIncomingLine[0] == "struct" || mIncomingLine[0] == "class") && finishing == '{'){ ClassElement * element = new ClassElement; element->name = mIncomingLine[1]; element->isStruct = (mIncomingLine[0] == "struct"); element->currentVisibility = element->isStruct ? Public : Private; push (element); return true; } // Case 4. Structure/Class derived from some other type if (mIncomingLine.size() > 3 && (mIncomingLine[0] == "struct" || mIncomingLine[0] == "class") && mIncomingLine[2] == ":"){ ClassElement * element = new ClassElement; element->name = mIncomingLine[1]; element->isStruct = (mIncomingLine[0] == "struct"); element->currentVisibility = element->isStruct ? Public : Private; StringVec::const_iterator i = mIncomingLine.begin() + 3; while (i != mIncomingLine.end()){ Visibility v = element->currentVisibility; if (*i == "public") { v = Public; i++; } if (*i == "private") { v = Private; i++; } if (*i == "protected"){ v = Protected; i++;} bool suc; StringVec::const_iterator end = matchTypeName (i, mIncomingLine.end(), &suc); if (!suc) { fprintf (stderr, "Error: could not match a typename\n"); delete element; return false; } ClassElement::Parent p; p.first = v; p.second = formatType (i,end); element->parents.push_back (p); i = end; if (i == mIncomingLine.end()) break; if (*i == ",") { i++; continue; } fprintf (stderr, "Error: Invalid character: %s\n", i->c_str()); delete element; return false; } push (element); return true; } // Case 5. Member Variable if (finishing == ';'){ VariableDefinition definition; bool result = matchVariableDefinition (mIncomingLine.begin(), mIncomingLine.end(), &definition); if (result) { if (mDebug) printf ("Matched variable definition: %s\n", sf::toJSON(definition).c_str()); StackElement * element = mStack.top(); if (element->type == StackElement::Class){ ClassElement * celement = static_cast<ClassElement*> (element); celement->memberVariables.push_back (std::make_pair(celement->currentVisibility,definition)); return true; } } } // Case 6a: Handling of SF_AUTOREFLECT_COMMAND; if (finishing == ';'){ size_t size = mIncomingLine.size(); if (size >= 1){ const std::string & x (mIncomingLine.back()); size_t prefix = beginsWidth (x, mCommandPrefix); if (prefix != x.npos){ std::string cmd = x.substr (prefix, x.npos); assert (!mStack.empty()); StackElement * element = mStack.top (); element->commands.insert (cmd); mIncomingLine.pop_back (); return true; } } } // Case 6b: handling of SF_AUTOREFLECT_COMMAND(element-name) if (finishing == ';'){ size_t size = mIncomingLine.size(); if (size >= 4){ const std::string & x (mIncomingLine.front()); size_t prefix = beginsWidth (x, mCommandPrefix); if (prefix != x.npos && mIncomingLine[1] == "(" && mIncomingLine[size-1] == ")"){ std::string cmd = x.substr (prefix, x.npos); StringVec::iterator beginType = mIncomingLine.begin() + 2; StringVec::iterator endType = mIncomingLine.end() - 1; bool suc; StringVec::const_iterator foundEnd = matchTypeName (beginType, endType, &suc); if (!suc) { fprintf (stderr, "Could not match a type name in %s command", cmd.c_str()); return false; } std::string elementName = formatType (beginType, foundEnd); StackElement * parent = mStack.top (); StackElement * child = parent->findChild (elementName); if (child){ child->commands.insert (cmd); mIncomingLine.erase(mIncomingLine.end() - 4, mIncomingLine.end()); return true; } else { fprintf (stderr, "Did not found a element with name %s as child of element of name %s, for command %s\n", elementName.c_str(), sf::toJSON(parent).c_str(), cmd.c_str()); return false; } } } } // Case 7 Function declaration if (finishing == ';' || finishing == '{') { FunctionDeclarationElement * declaration = new FunctionDeclarationElement(); bool result = matchFunctionDeclaration (mIncomingLine.begin(), mIncomingLine.end(), declaration); if (result) { if (mDebug) printf ("Matched function declaration %s\n", sf::toJSON (declaration).c_str()); StackElement * element = mStack.top(); if (element->type == StackElement::Class) declaration->visibility = (static_cast<ClassElement*> (element))->currentVisibility; if ( (element->type == StackElement::Class) || (element->type == StackElement::Root) || (element->type == StackElement::Namespace)){ element->children.push_back (declaration); } else { // May happen. Regular functions are similar to be parsed like functions // E.g. int bla () { X x ();} // must not declare x but can also declare an instance of (struct/class) X, called x. // fprintf (stderr, "Matched a function declaration %s outside a class/root/namespace element, parent=%s\n", sf::toJSON (declaration).c_str(), sf::toJSON (*element).c_str()); delete declaration; if (finishing != '{') // otherwise there is still a block return true; } } if (finishing != '{') // otherwise there is still a block return true; } // Unknown block, starting if (finishing == '{'){ if (mDebug){ printf ("Unknown block start: "); for (StringVec::const_iterator i = mIncomingLine.begin(); i != mIncomingLine.end(); i++){ printf ("%s ", i->c_str()); } printf ("<stop>\n"); } UnknownBlock * element = new UnknownBlock (); push (element); return true; } // End of a block, ending if (finishing == '}'){ bool ret = pop (); return ret; } // Command, ending if (finishing == ';'){ if (mDebug){ printf ("Unknown command: "); for (StringVec::const_iterator i = mIncomingLine.begin(); i != mIncomingLine.end(); i++){ printf ("%s ", i->c_str()); } printf ("<stop>\n"); } return true; } return true; }