// Look up each key binding in the config file and set the mappings for // all key combinations that trigger it. static void LoadConfigBindings() { std::map<CStr, CConfigValueSet> bindings = g_ConfigDB.GetValuesWithPrefix( CFG_COMMAND, "hotkey." ); CParser multikeyParser; multikeyParser.InputTaskType( "multikey", "<[~$arg(_negate)]$value_+_>_[~$arg(_negate)]$value" ); for( std::map<CStr, CConfigValueSet>::iterator bindingsIt = bindings.begin(); bindingsIt != bindings.end(); ++bindingsIt ) { std::string hotkeyName = bindingsIt->first.substr(7); // strip the "hotkey." prefix for( CConfigValueSet::iterator it = bindingsIt->second.begin(); it != bindingsIt->second.end(); ++it ) { std::string hotkey; if( it->GetString( hotkey ) ) { std::vector<SKey> keyCombination; CParserLine multikeyIdentifier; multikeyIdentifier.ParseString( multikeyParser, hotkey ); // Iterate through multiple-key bindings (e.g. Ctrl+I) bool negateNext = false; for( size_t t = 0; t < multikeyIdentifier.GetArgCount(); t++ ) { if( multikeyIdentifier.GetArgString( (int)t, hotkey ) ) { if( hotkey == "_negate" ) { negateNext = true; continue; } // Attempt decode as key name int mapping = FindKeyCode( hotkey ); // Attempt to decode as a negation of a keyname // Yes, it's going a bit far, perhaps. // Too powerful for most uses, probably. // However, it got some hardcoding out of the engine. // Thus it makes me happy. if( !mapping ) { LOGWARNING(L"Hotkey mapping used invalid key '%hs'", hotkey.c_str() ); continue; } SKey key = { (SDLKEY)mapping, negateNext }; keyCombination.push_back(key); negateNext = false; } } std::vector<SKey>::iterator itKey, itKey2; for( itKey = keyCombination.begin(); itKey != keyCombination.end(); ++itKey ) { SHotkeyMapping bindCode; bindCode.name = hotkeyName; bindCode.negated = itKey->negated; for( itKey2 = keyCombination.begin(); itKey2 != keyCombination.end(); ++itKey2 ) { // Push any auxiliary keys. if( itKey != itKey2 ) bindCode.requires.push_back( *itKey2 ); } g_HotkeyMap[itKey->code].push_back( bindCode ); } } } } }
void CGUIString::SetValue(const CStrW& str) { m_OriginalString = str; // clear m_TextChunks.clear(); m_Words.clear(); m_RawString = CStrW(); // Setup parser // TODO Gee: (2004-08-16) Create and store this parser object somewhere to save loading time. // TODO PT: Extended CParserCache so that the above is possible (since it currently only // likes one-task parsers) CParser Parser; // I've added the option of an additional parameter. Only used for icons when writing this. Parser.InputTaskType("start", "$ident[_=_$value_[$ident_=_$value_]]"); Parser.InputTaskType("end", "/$ident"); long position = 0; long from=0; // the position in the raw std::string where the last tag ended long from_nonraw=0; // like from only in position of the REAL std::string, with tags. long curpos = 0; // Current Text Chunk CGUIString::TextChunk CurrentTextChunk; for (;;position = curpos+1) { // Find next TagStart character curpos = str.Find(position, TagStart); if (curpos == -1) { m_RawString += str.substr(position); if (from != (long)m_RawString.length()) { CurrentTextChunk.m_From = from; CurrentTextChunk.m_To = (int)m_RawString.length(); m_TextChunks.push_back(CurrentTextChunk); } break; } else { // First check if there is another TagStart before a TagEnd, // in that case it's just a regular TagStart and we can continue. long pos_left = str.Find(curpos+1, TagStart); long pos_right = str.Find(curpos+1, TagEnd); if (pos_right == -1) { m_RawString += str.substr(position, curpos-position+1); continue; } else if (pos_left != -1 && pos_left < pos_right) { m_RawString += str.substr(position, pos_left-position); continue; } else { m_RawString += str.substr(position, curpos-position); // Okay we've found a TagStart and TagEnd, positioned // at pos and pos_right. Now let's extract the // interior and try parsing. CStrW tagstr (str.substr(curpos+1, pos_right-curpos-1)); CParserLine Line; Line.ParseString(Parser, tagstr.ToUTF8()); // Set to true if the tag is just text. bool justtext = false; if (Line.m_ParseOK) { if (Line.m_TaskTypeName == "start") { // The tag TextChunk::Tag tag; std::string Str_TagType; Line.GetArgString(0, Str_TagType); if (!tag.SetTagType(Str_TagType)) { justtext = true; } else { // Check for possible value-std::strings if (Line.GetArgCount() >= 2) Line.GetArgString(1, tag.m_TagValue); //Handle arbitrary number of additional parameters size_t argn; for(argn = 2; argn < Line.GetArgCount(); argn += 2) { TextChunk::Tag::TagAttribute a; Line.GetArgString(argn, a.attrib); Line.GetArgString(argn+1, a.value); tag.m_TagAttributes.push_back(a); } // Finalize last if (curpos != from_nonraw) { CurrentTextChunk.m_From = from; CurrentTextChunk.m_To = from + curpos - from_nonraw; m_TextChunks.push_back(CurrentTextChunk); from = CurrentTextChunk.m_To; } from_nonraw = pos_right+1; // Some tags does not have a closure, and should be // stored without text. Like a <tag /> in XML. if (tag.m_TagType == TextChunk::Tag::TAG_IMGLEFT || tag.m_TagType == TextChunk::Tag::TAG_IMGRIGHT || tag.m_TagType == TextChunk::Tag::TAG_ICON) { // We need to use a fresh text chunk // because 'tag' should be the *only* tag. TextChunk FreshTextChunk; // They does not work with the text system. FreshTextChunk.m_From = from + pos_right+1 - from_nonraw; FreshTextChunk.m_To = from + pos_right+1 - from_nonraw; FreshTextChunk.m_Tags.push_back(tag); m_TextChunks.push_back(FreshTextChunk); } else { // Add that tag, but first, erase previous occurences of the // same tag. std::vector<TextChunk::Tag>::iterator it; for (it = CurrentTextChunk.m_Tags.begin(); it != CurrentTextChunk.m_Tags.end(); ++it) { if (it->m_TagType == tag.m_TagType) { CurrentTextChunk.m_Tags.erase(it); break; } } // Add! CurrentTextChunk.m_Tags.push_back(tag); } } } else if (Line.m_TaskTypeName == "end") { // The tag TextChunk::Tag tag; std::string Str_TagType; Line.GetArgString(0, Str_TagType); if (!tag.SetTagType(Str_TagType)) { justtext = true; } else { // Finalize the previous chunk if (curpos != from_nonraw) { CurrentTextChunk.m_From = from; CurrentTextChunk.m_To = from + curpos - from_nonraw; m_TextChunks.push_back(CurrentTextChunk); from = CurrentTextChunk.m_To; } from_nonraw = pos_right+1; // Search for the tag, if it's not added, then // pass it as plain text. std::vector<TextChunk::Tag>::iterator it; for (it = CurrentTextChunk.m_Tags.begin(); it != CurrentTextChunk.m_Tags.end(); ++it) { if (it->m_TagType == tag.m_TagType) { CurrentTextChunk.m_Tags.erase(it); break; } } } } } else justtext = true; if (justtext) { // What was within the tags could not be interpreted // so we'll assume it's just text. m_RawString += str.substr(curpos, pos_right-curpos+1); } curpos = pos_right; continue; } } } // Add a delimiter at start and at end, it helps when // processing later, because we don't have make exceptions for // those cases. // We'll sort later. m_Words.push_back(0); m_Words.push_back((int)m_RawString.length()); // Space: ' ' for (position=0, curpos=0;;position = curpos+1) { // Find the next word-delimiter. long dl = m_RawString.Find(position, ' '); if (dl == -1) break; curpos = dl; m_Words.push_back((int)dl+1); } // Dash: '-' for (position=0, curpos=0;;position = curpos+1) { // Find the next word-delimiter. long dl = m_RawString.Find(position, '-'); if (dl == -1) break; curpos = dl; m_Words.push_back((int)dl+1); } // New Line: '\n' for (position=0, curpos=0;;position = curpos+1) { // Find the next word-delimiter. long dl = m_RawString.Find(position, '\n'); if (dl == -1) break; curpos = dl; // Add before and m_Words.push_back((int)dl); m_Words.push_back((int)dl+1); } sort(m_Words.begin(), m_Words.end()); // Remove duplicates (only if larger than 2) if (m_Words.size() > 2) { std::vector<int>::iterator it; int last_word = -1; for (it = m_Words.begin(); it != m_Words.end(); ) { if (last_word == *it) { it = m_Words.erase(it); } else { last_word = *it; ++it; } } } #if 0 for (int i=0; i<(int)m_Words.size(); ++i) { LOGMESSAGE(L"m_Words[%d] = %d", i, m_Words[i]); } for (int i=0; i<(int)m_TextChunks.size(); ++i) { LOGMESSAGE(L"m_TextChunk[%d] = [%d,%d]", i, m_TextChunks[i].m_From, m_TextChunks[i].m_To); for (int j=0; j<(int)m_TextChunks[i].m_Tags.size(); ++j) { LOGMESSAGE(L"--Tag: %d \"%hs\"", (int)m_TextChunks[i].m_Tags[j].m_TagType, m_TextChunks[i].m_Tags[j].m_TagValue.c_str()); } } #endif }
bool CConfigDB::Reload(EConfigNamespace ns) { if (ns < 0 || ns >= CFG_LAST) { debug_warn(L"CConfigDB: Invalid ns value"); return false; } // Set up CParser CParser parser; CParserLine parserLine; parser.InputTaskType("Assignment", "_$ident_=<_[-$arg(_minus)]_$value_,>_[-$arg(_minus)]_$value[[;]$rest]"); parser.InputTaskType("CommentOrBlank", "_[;[$rest]]"); // Open file with VFS shared_ptr<u8> buffer; size_t buflen; { // Handle missing files quietly if (g_VFS->GetFileInfo(m_ConfigFile[ns], NULL) < 0) { LOGMESSAGE(L"Cannot find config file \"%ls\" - ignoring", m_ConfigFile[ns].string().c_str()); return false; } else { LOGMESSAGE(L"Loading config file \"%ls\"", m_ConfigFile[ns].string().c_str()); Status ret = g_VFS->LoadFile(m_ConfigFile[ns], buffer, buflen); if (ret != INFO::OK) { LOGERROR(L"CConfigDB::Reload(): vfs_load for \"%ls\" failed: return was %lld", m_ConfigFile[ns].string().c_str(), (long long)ret); return false; } } } TConfigMap newMap; char *filebuf=(char *)buffer.get(); char *filebufend=filebuf+buflen; // Read file line by line char *next=filebuf-1; do { char *pos=next+1; next=(char *)memchr(pos, '\n', filebufend-pos); if (!next) next=filebufend; char *lend=next; if (lend > filebuf && *(lend-1) == '\r') lend--; // Send line to parser bool parseOk=parserLine.ParseString(parser, std::string(pos, lend)); // Get name and value from parser std::string name; std::string value; if (parseOk && parserLine.GetArgCount()>=2 && parserLine.GetArgString(0, name) && parserLine.GetArgString(1, value)) { // Add name and value to the map size_t argCount = parserLine.GetArgCount(); newMap[name].clear(); for( size_t t = 0; t < argCount; t++ ) { if( !parserLine.GetArgString( (int)t + 1, value ) ) continue; CConfigValue argument; argument.m_String = value; newMap[name].push_back( argument ); LOGMESSAGE(L"Loaded config string \"%hs\" = \"%hs\"", name.c_str(), value.c_str()); } } } while (next < filebufend); m_Map[ns].swap(newMap); return true; }
void CTerrainProperties::LoadXml(XMBElement node, CXeromyces *pFile, const VfsPath& UNUSED(pathname)) { #define ELMT(x) int elmt_##x = pFile->GetElementID(#x) #define ATTR(x) int attr_##x = pFile->GetAttributeID(#x) // Terrain Attribs ATTR(mmap); ATTR(groups); ATTR(movementclass); ATTR(angle); ATTR(size); #undef ELMT #undef ATTR XERO_ITER_ATTR(node, attr) { if (attr.Name == attr_groups) { // Parse a comma-separated list of groups, add the new entry to // each of them CParser parser; CParserLine parserLine; parser.InputTaskType("GroupList", "<_$value_,>_$value_"); if (!parserLine.ParseString(parser, attr.Value)) continue; m_Groups.clear(); for (size_t i=0;i<parserLine.GetArgCount();i++) { std::string value; if (!parserLine.GetArgString(i, value)) continue; CTerrainGroup *pType = g_TexMan.FindGroup(value); m_Groups.push_back(pType); } } else if (attr.Name == attr_mmap) { CColor col; if (!col.ParseString(attr.Value, 255)) continue; // m_BaseColor is BGRA u8 *baseColor = (u8*)&m_BaseColor; baseColor[0] = (u8)(col.b*255); baseColor[1] = (u8)(col.g*255); baseColor[2] = (u8)(col.r*255); baseColor[3] = (u8)(col.a*255); m_HasBaseColor = true; } else if (attr.Name == attr_angle) { m_TextureAngle = DEGTORAD(attr.Value.ToFloat()); } else if (attr.Name == attr_size) { m_TextureSize = attr.Value.ToFloat(); } else if (attr.Name == attr_movementclass) { m_MovementClass = attr.Value; } } }