1 #include "optionswrapper.h"
2 
3 #include "unitsync.h"
4 #include <lslutils/conversion.h>
5 #include <lslutils/debug.h>
6 #include <lslutils/logging.h>
7 
8 #include <stdexcept>
9 #include <clocale>
10 
11 namespace LSL {
12 
OptionsWrapper()13 OptionsWrapper::OptionsWrapper()
14 {
15 	unLoadOptions();
16     loadOptions( EngineOption, "" );
17     loadOptions( PrivateOptions,"" );
18 }
19 
unLoadOptions()20 void OptionsWrapper::unLoadOptions()
21 {
22 	for (int i = 0; i < LastOption; ++i)
23 	{
24 		unLoadOptions( (GameOption)i );
25 	}
26 }
27 
unLoadOptions(GameOption i)28 void OptionsWrapper::unLoadOptions(GameOption i)
29 {
30   GameOptions empty;
31   m_opts[i] = empty;
32 
33 	mmSectionTreeMap::iterator itor = m_sections.find( i );
34 	if ( itor != m_sections.end() ) m_sections.erase( itor );
35 }
36 
~OptionsWrapper()37 OptionsWrapper::~OptionsWrapper()
38 {
39 }
40 
loadMapOptions(const std::string & mapname)41 bool OptionsWrapper::loadMapOptions( const std::string& mapname)
42 {
43 	return loadOptions(MapOption,mapname);
44 }
45 
GetSingleOptionType(const std::string & key) const46 Enum::OptionType OptionsWrapper::GetSingleOptionType ( const std::string& key) const
47 {
48     Enum::OptionType type = Enum::opt_undefined;
49 	for ( int g = 0; g < LastOption; g++ )
50 	{
51 		if (keyExists(key,(GameOption)g,false,type))
52 			return type;
53 	}
54     return Enum::opt_undefined;
55 }
56 
loadAIOptions(const std::string & modname,int aiindex,const std::string & ainame)57 bool OptionsWrapper::loadAIOptions( const std::string& modname, int aiindex,const std::string& ainame )
58 {
59 	int mapindex = m_ais_indexes[ainame];
60 	if ( mapindex == 0 ) mapindex = m_ais_indexes.size() + LastOption;
61 	m_ais_indexes[ainame] = mapindex;
62 	unLoadOptions((GameOption)mapindex);
63 	try
64 	{
65 		GameOptions opt = usync().GetAIOptions( modname, aiindex );
66 		ParseSectionMap( m_sections[mapindex], opt.section_map );
67 		m_opts[mapindex] = opt;
68 	} catch (...)
69 	{
70 		return false;
71 	}
72 	return true;
73 }
74 
GetAIOptionIndex(const std::string & nick) const75 int OptionsWrapper::GetAIOptionIndex( const std::string& nick ) const
76 {
77 	std::map<std::string,int>::const_iterator itor = m_ais_indexes.find(nick);
78 	int pos = -1;
79 	if ( itor != m_ais_indexes.end() ) pos = itor->second;
80 	return pos;
81 }
82 
loadOptions(GameOption modmapFlag,const std::string & name,const std::string & extra_filename)83 bool OptionsWrapper::loadOptions( GameOption modmapFlag, const std::string& name, const std::string& extra_filename )
84 {
85 	unLoadOptions(modmapFlag);
86 	GameOptions opt;
87 	switch (modmapFlag)
88 	{
89 	    default:
90             break;
91 		case MapOption:
92 			try
93 			{
94                 opt = usync().GetMapOptions(name);
95                 ParseSectionMap( m_sections[modmapFlag], opt.section_map );
96 			}
97 			catch(...)
98 			{
99                 LslError("Could not load map options");
100 				return false;
101 			}
102 			break;
103 
104 		case ModOption:
105 			try
106 			{
107                 opt = usync().GetModOptions(name);
108                 ParseSectionMap( m_sections[modmapFlag], opt.section_map );
109 			}
110 			catch(...)
111 			{
112                 LslError("Could not load game options");
113 				return false;
114 			}
115 			break;
116 
117         case EngineOption: {
118             //TODO Fixed,random and so forth are intls
119             mmOptionList startpos( "Start Position Type", "startpostype", "How players will select where to be spawned in the map\n0: fixed map positions\n1: random map positions\n2: choose in game\n3: choose in the lobby before starting", "0" );
120             startpos.addItem( "0", "Fixed", "Use the start positions defined in the map, the positions will be assigned incrementally from the team with lowest number to highest");
121             startpos.addItem( "1", "Random", "Use the start positions defined in the map, the positions will be assigned randomly");
122             startpos.addItem( "2", "Choose in-game", "Players will be able to pick their own starting point right before the game starts, optionally limited by a bounding box defined by the host");
123             startpos.addItem( "3", "Choose before game", "The host will place each player's start position in the map preview before the game is launched");
124             opt.list_map["startpostype"] = startpos;
125             break;
126         }
127 
128         case PrivateOptions: {
129             opt.string_map["restrictions"] = mmOptionString("List of restricted units", "restrictedunits", "Units in this list won't be available in game", "", 0 ); // tab separated list
130             opt.string_map["mapname"] = mmOptionString("Map name", "mapname", "Map name", "", 0 );
131             break;
132         }
133 
134         case ModCustomizations: {
135             try {
136                 opt = usync().GetModCustomizations( name );
137             }
138             catch(...) {
139                 LslError("Could not load mod customizations");
140 				return false;
141 			}
142 			break;
143         }
144 
145         case SkirmishOptions: {
146             try {
147                 opt = usync().GetSkirmishOptions( name, extra_filename );
148             }
149             catch(...) {
150                 LslError("Could not load skirmish options");
151 				return false;
152 			}
153 			break;
154         }
155 	}
156 	m_opts[modmapFlag] = opt;
157 	return true;
158 }
159 
GetSection(const std::string & key) const160 OptionsWrapper::GameOption OptionsWrapper::GetSection( const std::string& key ) const
161 {
162 	GameOption ret = LastOption;
163 	bool found = false;
164 	for ( int flag = 0; flag < PrivateOptions; flag++ )
165 	{
166         Enum::OptionType optType = Enum::opt_undefined;
167 		found = keyExists( key, (GameOption)flag, false, optType );
168 		if ( found )
169 		{
170 			 ret = (GameOption)flag;
171 			 break;
172 		}
173 	}
174 	return ret;
175 }
176 
keyExists(const std::string & key) const177 bool OptionsWrapper::keyExists( const std::string& key ) const
178 {
179 	bool found = false;
180 	for ( int flag = 0; flag < PrivateOptions; flag++ )
181 	{
182         Enum::OptionType optType = Enum::opt_undefined;
183 		found = keyExists( key, (GameOption)flag, false, optType );
184 		if ( found ) break;
185 	}
186 	return found;
187 }
188 
keyExists(const std::string & key,const GameOption modmapFlag,bool showError,Enum::OptionType & optType) const189 bool OptionsWrapper::keyExists( const std::string& key, const GameOption modmapFlag, bool showError, Enum::OptionType& optType ) const
190 {
191     //std::string duplicateKeyError = "Please contact the game's author and tell him\nto use unique keys in his ModOptions.lua";
192 	bool exists = false;
193     optType = Enum::opt_undefined;
194     GameOptionsMap::const_iterator optIt = m_opts.find((int)modmapFlag);
195     if ( optIt == m_opts.end() )
196         return false;
197 	const GameOptions& gameoptions = optIt->second;
198 	if (  gameoptions.list_map.find(key) !=  gameoptions.list_map.end())
199 	{
200         optType = Enum::opt_list;
201 		exists = true;
202 	}
203 	else if ( gameoptions.string_map.find(key) !=  gameoptions.string_map.end())
204 	{
205         optType = Enum::opt_string;
206 		exists = true;
207 	}
208 	else if ( gameoptions.bool_map.find(key) !=  gameoptions.bool_map.end())
209 	{
210         optType = Enum::opt_bool;
211 		exists = true;
212 	}
213 	else if ( gameoptions.float_map.find(key)!=  gameoptions.float_map.end())
214 	{
215         optType = Enum::opt_float;
216 		exists = true;
217 	}
218 	else if ( gameoptions.section_map.find(key)!=  gameoptions.section_map.end())
219 	{
220         optType = Enum::opt_section;
221 		exists = true;
222 	}
223 	if (exists && showError)
224 	{
225         //TODO STH
226 //		customMessageBoxNoModal(SL_MAIN_ICON,duplicateKeyError, "Mod/map option error",wxOK);
227         LslWarning("duplicate key in mapmodoptions");
228 		return false;
229 	}
230 	else if ( exists && !showError )
231 	{
232         return true;
233 	}
234 	else
235 		return false;
236 }
237 
setOptions(stringPairVec * options,GameOption modmapFlag)238 bool OptionsWrapper::setOptions(stringPairVec* options, GameOption modmapFlag)
239 {
240     for (stringPairVec::const_iterator it = options->begin(); it != options->end(); ++it)
241 	{
242 		std::string key = it->first;
243 		std::string value = it->second;
244 
245 		//we don't want to add a key that doesn't already exists
246         Enum::OptionType optType = Enum::opt_undefined;
247 		if(!keyExists(key,modmapFlag,false,optType))
248 			return false;
249 		else
250 		{
251 			if ( !setSingleOptionTypeSwitch( key, value, modmapFlag, optType) )
252 				return false;
253 		}
254 	}
255 	return true;
256 }
257 
getOptions(GameOption modmapFlag) const258 OptionsWrapper::stringTripleVec OptionsWrapper::getOptions( GameOption modmapFlag) const
259 {
260     stringTripleVec list;
261     GameOptionsMapCIter optIt = m_opts.find((int)modmapFlag);
262     if ( optIt != m_opts.end() ) {
263         const GameOptions& gameoptions = optIt->second;
264         for (OptionMapBoolConstIter it = gameoptions.bool_map.begin(); it != gameoptions.bool_map.end(); ++it) {
265             list.push_back( stringTriple( (*it).first, stringPair ( it->second.name , Util::ToString(it->second.value) ) ) );
266         }
267 
268         for (OptionMapStringConstIter it = gameoptions.string_map.begin(); it != gameoptions.string_map.end(); ++it) {
269             list.push_back( stringTriple( (*it).first, stringPair ( it->second.name, it->second.value) ) );
270         }
271 
272         for (OptionMapFloatConstIter it = gameoptions.float_map.begin(); it != gameoptions.float_map.end(); ++it) {
273             list.push_back( stringTriple( (*it).first, stringPair ( it->second.name, Util::ToString(it->second.value) ) ) );
274         }
275 
276         for (OptionMapListConstIter it = gameoptions.list_map.begin(); it != gameoptions.list_map.end(); ++it) {
277             list.push_back( stringTriple( (*it).first, stringPair ( it->second.name, it->second.value ) ) );
278         }
279     }
280 	return list;
281 }
282 
getOptionsMap(GameOption modmapFlag) const283 std::map<std::string,std::string> LSL::OptionsWrapper::getOptionsMap( GameOption modmapFlag ) const
284 {
285     std::map<std::string,std::string> map;
286     GameOptionsMapCIter optIt = m_opts.find((int)modmapFlag);
287     if ( optIt != m_opts.end() ) {
288         const GameOptions& gameoptions = optIt->second;
289         for (OptionMapBoolConstIter it = gameoptions.bool_map.begin(); it != gameoptions.bool_map.end(); ++it) {
290             map[it->first] =  Util::ToString(it->second.value);
291         }
292 
293         for (OptionMapStringConstIter it = gameoptions.string_map.begin(); it != gameoptions.string_map.end(); ++it) {
294             map[it->first] = it->second.value;
295         }
296 
297         for (OptionMapFloatConstIter it = gameoptions.float_map.begin(); it != gameoptions.float_map.end(); ++it) {
298             map[it->first] = Util::ToString(it->second.value);
299         }
300 
301         for (OptionMapListConstIter it = gameoptions.list_map.begin(); it != gameoptions.list_map.end(); ++it) {
302             map[it->first] = it->second.value;
303         }
304     }
305 	return map;
306 }
307 
setSingleOption(const std::string & key,const std::string & value,GameOption modmapFlag)308 bool OptionsWrapper::setSingleOption( const std::string& key, const std::string& value,GameOption modmapFlag)
309 {
310     Enum::OptionType optType = Enum::opt_undefined;
311 	keyExists( key, modmapFlag, false, optType );
312 	return setSingleOptionTypeSwitch(key,value,modmapFlag,optType);
313 }
314 
setSingleOption(const std::string & key,const std::string & value)315 bool OptionsWrapper::setSingleOption( const std::string& key, const std::string& value )
316 {
317     Enum::OptionType optType = Enum::opt_undefined;
318 	if (keyExists(key,ModOption,false,optType))
319 		return setSingleOptionTypeSwitch(key,value,ModOption,optType);
320 	else if (keyExists(key,MapOption,false,optType))
321 		return setSingleOptionTypeSwitch(key,value,MapOption,optType);
322 	else
323 		return false;
324 }
325 
getSingleValue(const std::string & key) const326 std::string OptionsWrapper::getSingleValue( const std::string& key) const
327 {
328 	for ( int g = 0; g < LastOption; g++ )
329 	{
330 		const std::string tmp = getSingleValue(key, (GameOption)g);
331         if (tmp != "")
332 			return tmp;
333 	}
334     return "";
335 }
336 template < class MapType >
GetItem(const MapType & map,const typename MapType::key_type & key)337 static inline typename MapType::mapped_type GetItem( const MapType& map, const typename MapType::key_type& key )
338 {
339     typename MapType::const_iterator mapIt = map.find(key);
340     if ( mapIt != map.end() )
341         return mapIt->second;
342     else
343         return typename MapType::mapped_type();
344 }
345 
getSingleValue(const std::string & key,GameOption modmapFlag) const346 std::string OptionsWrapper::getSingleValue( const std::string& key, GameOption modmapFlag) const
347 {
348     Enum::OptionType optType = Enum::opt_undefined;
349 
350 	if ( keyExists(key,modmapFlag,false,optType) )
351 	{
352         GameOptionsMapCIter optIt = m_opts.find((int)modmapFlag);
353         if ( optIt == m_opts.end() )
354             return "";
355 
356         const GameOptions& tempOpt = optIt->second;
357 		switch (optType)
358 		{
359         case Enum::opt_float:
360             return Util::ToString( GetItem( tempOpt.float_map, key ).value );
361         case Enum::opt_bool:
362             return Util::ToString( GetItem( tempOpt.bool_map, key ).value );
363         case Enum::opt_string:
364 			return  GetItem( tempOpt.string_map, key ).value ;
365         case Enum::opt_list:
366 			return GetItem( tempOpt.list_map, key ).value;
367         case Enum::opt_undefined:
368         default:
369             return "";
370 		}
371 	}
372     return "";
373 }
374 
getDefaultValue(const std::string & key,GameOption modmapFlag) const375 std::string OptionsWrapper::getDefaultValue( const std::string& key, GameOption modmapFlag) const
376 {
377     Enum::OptionType optType = Enum::opt_undefined;
378 	std::string ret;
379 	if ( keyExists(key,modmapFlag,false,optType) )
380 	{
381 			//purposefully create a copy, no better idea
382         GameOptionsMapCIter optIt = m_opts.find((int)modmapFlag);
383         if ( optIt == m_opts.end() )
384             return "";
385 
386         const GameOptions& tempOpt = optIt->second;
387 		switch ( optType )
388 		{
389 			{
390             case Enum::opt_bool:
391                 ret = Util::ToString( GetItem( tempOpt.bool_map, key ).def );
392 				break;
393 			}
394             case Enum::opt_float:
395 			{
396                 ret = Util::ToString( GetItem( tempOpt.float_map, key ).def );
397 				break;
398 			}
399             case Enum::opt_string:
400 			{
401 				ret = GetItem( tempOpt.string_map, key ).def;
402 				break;
403 			}
404             case Enum::opt_list:
405 			{
406 				ret = GetItem( tempOpt.list_map, key ).def;
407 				break;
408 			}
409 			default:
410 			{
411 				break;
412 			}
413 		}
414 	}
415 	return ret;
416 }
417 
setSingleOptionTypeSwitch(const std::string & key,const std::string & value,GameOption modmapFlag,Enum::OptionType optType)418 bool  LSL::OptionsWrapper::setSingleOptionTypeSwitch( const std::string& key, const std::string& value, GameOption modmapFlag, Enum::OptionType optType)
419 {
420 	GameOptions& gameoptions = m_opts[modmapFlag];
421 	switch (optType)
422 	{
423         case Enum::opt_float :
424 		{
425 			//temp set to C locale cause we get '.' as decimal seperator over the net
426 			const char* old_locale = std::setlocale(LC_NUMERIC, "C");
427 			//test if min < val < max
428 			const double d_val = Util::FromString<double>( value );
429 			std::setlocale(LC_NUMERIC, old_locale);
430 			if( d_val < (gameoptions.float_map)[key].min || d_val > (gameoptions.float_map)[key].max )
431 			{
432                 LslDebug("received number option exceeds boundaries");
433 				return false;
434 			}
435 			else
436 				(gameoptions.float_map)[key].value = d_val;
437 			break;
438 		}
439         case Enum::opt_bool :
440 		{
441 			const long l_val = Util::FromString<long>( value );
442 			if( l_val != 1 && l_val != 0 )
443 			{
444                 LslDebug("recieved bool option that is neither 0 or 1");
445 				return false;
446 			}
447 			else
448 				(gameoptions.bool_map)[key].value = bool(l_val);
449 			break;
450 		}
451         case Enum::opt_string :
452 		{
453 			// test if maxlength isn't exceeded
454 			unsigned int max_length = (gameoptions.string_map)[key].max_len;
455             if ( ( max_length != 0 ) && ( value.length() > max_length )  )
456 			{
457                 LslDebug("recieved string option exceeds max_len");
458 				return false;
459 			}
460 			else
461 				(gameoptions.string_map)[key].value = value;
462 			break;
463 		}
464         case Enum::opt_list :
465 		{
466 			// test if valid value, aka is in list
467 			int listitemcount = (gameoptions.list_map)[key].listitems.size();
468 			bool valid_string = false;
469 			int j = 0;
470 			for (; j < listitemcount; ++j)
471 			{
472 				if ( (gameoptions.list_map)[key].listitems[j].key == value)
473 				{
474 					valid_string = true;
475 					break;
476 				}
477 			}
478 
479 			if (valid_string)
480 			{
481 			    //LOOKATME (koshi) if there's a problem with list modoption look here first
482 				(gameoptions.list_map)[key].value = (gameoptions.list_map)[key].listitems[j].key;
483 				(gameoptions.list_map)[key].cur_choice_index = j;
484 			}
485 			else
486 			{
487                 LslDebug("received list option is not valid");
488 				return false;
489 			}
490 			break;
491 		}
492 		default:
493 			return false;
494 	}
495 	//if we made it here, all is good
496 	return true;
497 }
498 
GetNameListOptValue(const std::string & key,GameOption flag) const499 std::string OptionsWrapper::GetNameListOptValue( const std::string& key, GameOption flag) const
500 {
501     Enum::OptionType optType;
502 	if ( keyExists(key,flag,false, optType) )
503 	{
504         if ( optType == Enum::opt_list)
505 		{
506             GameOptionsMapCIter optIt = m_opts.find((int)flag);
507             if ( optIt == m_opts.end() )
508                 return "";
509 
510             GameOptions tempOpt = optIt->second;
511 			return ( (tempOpt.list_map)[key].cbx_choices[ (tempOpt.list_map)[key].cur_choice_index ] );
512 		}
513 	}
514 	// at this point retrieval failed
515     return "";
516 }
517 
GetNameListOptItemKey(const std::string & optkey,const std::string & itemname,GameOption flag) const518 std::string OptionsWrapper::GetNameListOptItemKey( const std::string& optkey, const std::string& itemname, GameOption flag) const
519 {
520     Enum::OptionType optType;
521 	if ( keyExists(optkey,flag,false, optType) )
522 	{
523         if ( optType == Enum::opt_list)
524 		{
525             GameOptionsMapCIter optIt = m_opts.find((int)flag);
526             if ( optIt == m_opts.end() )
527                 return "";
528 
529             GameOptions tempOpt = optIt->second;
530 			for (ListItemVec::const_iterator it = (tempOpt.list_map)[optkey].listitems.begin(); it != (tempOpt.list_map)[optkey].listitems.end(); ++it)
531 			{
532 				if (it->name == itemname)
533 					return it->key;
534 			}
535 		}
536 	}
537 
538 	// at this point retrieval failed
539     return "";
540 }
541 
MergeOptions(const OptionsWrapper & other,GameOption merge_into)542 bool OptionsWrapper::MergeOptions( const OptionsWrapper& other, GameOption merge_into )
543 {
544     GameOptionsMapCIter other_it = other.m_opts.begin();
545     for ( ; other_it != other.m_opts.end(); ++other_it ) {
546         const GameOptions& other_opts = other_it->second;
547         //const GameOption other_id = (const GameOption)other_it->first; //TODO (koshi) what was this supposed to be used for?
548 
549         for (OptionMapBoolConstIter it = other_opts.bool_map.begin(); it != other_opts.bool_map.end();++it ) {
550             m_opts[merge_into].bool_map[it->first] = it->second;
551         }
552 
553         for ( OptionMapFloatConstIter it = other_opts.float_map.begin(); it != other_opts.float_map.end(); ++it ) {
554             m_opts[merge_into].float_map[it->first] = it->second;
555         }
556 
557         for ( OptionMapListConstIter it = other_opts.list_map.begin(); it != other_opts.list_map.end(); ++it ){
558             m_opts[merge_into].list_map[it->first] = it->second;
559         }
560 
561         for ( OptionMapStringConstIter it = other_opts.string_map.begin(); it != other_opts.string_map.end(); ++it ) {
562             m_opts[merge_into].string_map[it->first] = it->second;
563         }
564     }
565     return true;
566 }
567 
ParseSectionMap(mmSectionTree & section_tree,const OptionMapSection & section_map)568 void OptionsWrapper::ParseSectionMap( mmSectionTree& section_tree, const OptionMapSection& section_map )
569 {
570 
571     // map child-key <-> parent-key
572     typedef std::map<std::string,std::string> RelationMap;
573 	typedef std::map<std::string,std::string>::iterator RelationMapIter;
574     RelationMap relation_map;
575 
576     //setup relation map
577     for ( OptionMapSectionConstIter it = section_map.begin(); it != section_map.end(); ++it )
578     {
579         relation_map[it->second.key] = it->second.section;
580     }
581 
582     RelationMapIter rit = relation_map.begin();
583     // no more items in the map means we've added them all
584     while ( !relation_map.empty() )
585     {
586         RelationMapIter rit_next = rit; // in case we need to delete
587         ++rit_next;
588 
589         if ( relation_map.find(rit->second) == relation_map.end() )
590         {
591             //either we already added this sections parent or it's a root section
592             OptionMapSectionConstIter section = section_map.find(rit->first);
593             assert ( section != section_map.end() );
594                 section_tree.AddSection( section->second );
595 
596 
597               //we're done with this section, so remove it
598             relation_map.erase(rit);
599         }
600 
601         rit = rit_next;
602 
603         //we've reached the end of the map, restart at beginning
604         if ( rit == relation_map.end() )
605             rit = relation_map.begin();
606     }
607 
608 }
609 
610 const std::string tree_sep = "/";
611 
mmSectionTree()612 mmSectionTree::mmSectionTree()
613 	: m_tree ( new ConfigType() )
614 {
615 	//this class is basically nonfunctional atm
616 	//FIXME: assert( false );
617 }
618 
~mmSectionTree()619 mmSectionTree::~mmSectionTree()
620 {
621     #ifndef NDEBUG
622 //		m_tree->Flush();
623 	#else //no need to clutter tempfile directory if we're not debugging
624 //		m_tree->DeleteAll();
625     #endif
626 }
627 
AddSection(const std::string & parentpath,const mmOptionSection & section)628 void mmSectionTree::AddSection ( const std::string& parentpath, const mmOptionSection& section )
629 {
630 //FIXME
631 //	std::string fullpath = parentpath + tree_sep + section.key + tree_sep;
632 //	m_tree->Write( fullpath + "key", section.key );
633 	#ifndef NDEBUG
634 //		m_tree->Flush();
635 	#endif
636 }
AddSection(const mmOptionSection & section)637 void mmSectionTree::AddSection( const mmOptionSection& section)
638 {
639 	//m_section_map[section.key] = section;
640 	std::string name = section.section;
641 	if ( section.section == Constants::nosection_name )
642 	{
643 		AddSection( tree_sep, section );
644 	}
645 	else
646 	{
647 		std::string parent = FindParentpath( section.section );
648 		AddSection( parent, section );
649 	}
650 }
651 
FindRecursive(const std::string &,std::string &)652 bool mmSectionTree::FindRecursive( const std::string& /*parent_key*/, std::string& /*path */)
653 {
654 //    std::string current;
655 //    long cur_index;
656 
657 //    //search current level first before recursing
658 //    bool cont = m_tree->GetFirstGroup( current, cur_index );
659 //    while ( cont )
660 //    {
661 //        if ( current.EndsWith( parent_key ) ) {
662 //            path = current;
663 //            return true;
664 //        }
665 //        cont = m_tree->GetNextGroup( current, cur_index );
666 //    }
667 
668 //    //we need to recurse into sub-paths
669 //    cont = m_tree->GetFirstGroup( current, cur_index );
670 //    while ( cont )
671 //    {
672 //        std::string old_path = m_tree->GetPath();
673 //        m_tree->SetPath( old_path + "/" + current );
674 //        if ( FindRecursive( parent_key,  path ) )
675 //            return true;
676 //        m_tree->SetPath( old_path );
677 //        cont = m_tree->GetNextGroup( current, cur_index );
678 //    }
679     return false;
680 }
681 
FindParentpath(const std::string & parent_key)682 std::string mmSectionTree::FindParentpath ( const std::string& parent_key )
683 {
684 	std::string path = tree_sep;
685     if ( FindRecursive( parent_key, path ) )
686         return path;
687     else
688         return "";
689 }
690 
Clear()691 void mmSectionTree::Clear()
692 {
693     m_section_map.clear();
694 //    m_tree->DeleteAll();
695 }
696 
697 } // namespace LSL {
698