Esempio n. 1
0
bool ReadChild (CPrimitiveClass::CChild &child, xmlNodePtr childNode, const char *filename, bool _static, CLigoConfig &config)
{
	// Read the class name
	if (!config.getPropertyString (child.ClassName, filename, childNode, "CLASS_NAME"))
		goto failed;

	// Read the name
	if (!_static || config.getPropertyString (child.Name, filename, childNode, "NAME"))
	{
		// Read the parameters
		child.Parameters.reserve (CIXml::countChildren (childNode, "PARAMETER"));
		for (	xmlNodePtr childParamNode = CIXml::getFirstChildNode (childNode, "PARAMETER");
				childParamNode != NULL;
				childParamNode = CIXml::getNextChildNode (childParamNode, "PARAMETER"))
		{
			// Add a static child
			child.Parameters.push_back (CPrimitiveClass::CInitParameters ());

			// Child ref
			CPrimitiveClass::CInitParameters &childParam = child.Parameters.back ();

			// Read the class name
			if (!config.getPropertyString (childParam.Name, filename, childParamNode, "NAME"))
				goto failed;

			// Read the parameters
			uint defaultId = 0;
			childParam.DefaultValue.resize (CIXml::countChildren (childParamNode, "DEFAULT_VALUE"));
			for (	xmlNodePtr childParamValueNode = CIXml::getFirstChildNode (childParamNode, "DEFAULT_VALUE");
					childParamValueNode != NULL;
					childParamValueNode = CIXml::getNextChildNode (childParamValueNode, "DEFAULT_VALUE"))
			{
				// Gen id flag
				childParam.DefaultValue[defaultId].GenID = false;

				// Read the gen id flag
				string value;
				if (CIXml::getPropertyString (value, childParamValueNode, "GEN_ID") && (value != "false"))
				{
					childParam.DefaultValue[defaultId].GenID = true;
				}
				else
				{
					if (!config.getPropertyString (value, filename, childParamValueNode, "VALUE"))
						goto failed;

					childParam.DefaultValue[defaultId].Name = value;
				}
				defaultId++;
			}
		}

		// Ok
		return true;
	}
failed:
	return false;
}
Esempio n. 2
0
bool ReadBool (const char *propName, bool &result, xmlNodePtr xmlNode, const char *filename, CLigoConfig &config)
{
	string str;
	if (CIXml::getPropertyString (str, xmlNode, propName))
	{
		if (str == "true")
			result = true;
		else if (str == "false")
			result = false;
		else
		{
			config.syntaxError (filename, xmlNode, "Unknown (%s) parameter (%s), should be false or true", propName, str.c_str ());
			return false;
		}
		return true;
	}
	return false;
}
Esempio n. 3
0
// ***************************************************************************
bool CMaxToLigo::loadLigoConfigFile (CLigoConfig& config, Interface& it, bool dialog)
{
	// Get the module path
	HMODULE hModule = hInstance;
	if (hModule)
	{
		// Get the path
		char sModulePath[256];
		int res=GetModuleFileName(hModule, sModulePath, 256);

		// Success ?
		if (res)
		{
			// Path
			char sDrive[256];
			char sDir[256];
			_splitpath (sModulePath, sDrive, sDir, NULL, NULL);
			_makepath (sModulePath, sDrive, sDir, "ligoscape", ".cfg");

			try
			{
				// Load the config file
				config.readConfigFile (sModulePath, false);

				// ok
				return true;
			}
			catch (Exception& e)
			{
				// Print an error message
				char msg[512];
				smprintf (msg, 512, "Error loading the config file ligoscape.cfg: %s", e.what());
				errorMessage (msg, "NeL Ligo load config file", it, dialog);
			}
		}
	}

	// Can't found the module
	return false;
}
Esempio n. 4
0
bool CPrimitiveClass::read (xmlNodePtr primitiveNode,
							const char *filename,
							const char *className,
							std::set<std::string> &contextStrings,
							std::map<std::string, std::string> &contextFilesLookup,
							CLigoConfig &config,
							bool parsePrimitiveComboContent)
{
	//	init default parameters
	AutoInit = false;
	Deletable = true;
	FileExtension = "";
	FileType = "";
	Collision = false;
	LinkBrothers = false;
	ShowArrow = true;
	Numberize = true;
	Visible = true;

	// read parent class properties
	string parentClass;
	if (CIXml::getPropertyString (parentClass, primitiveNode, "PARENT_CLASS"))
	{
		const CPrimitiveClass *parent = config.getPrimitiveClass(parentClass.c_str());

		if (parent == NULL)
		{
			config.syntaxError (filename, primitiveNode, "Can't find parent class (%s) for class (%s)", parentClass.c_str (), className);
			return false;
		}

		// copy all the properties
		*this = *parent;
	}

	// The name
	Name = className;

	// Read the type
	std::string type;
	if (!config.getPropertyString (type, filename, primitiveNode, "TYPE"))
		goto failed;

	// Good type ?
	if (type == "node")
		Type = Node;
	else if (type == "point")
		Type = Point;
	else if (type == "path")
		Type = Path;
	else if (type == "zone")
		Type = Zone;
	else if (type == "bitmap")
		Type = Bitmap;
	else if (type == "alias")
		Type = Alias;
	else
	{
		config.syntaxError (filename, primitiveNode, "Unknown primitive type (%s)", type.c_str ());
		goto failed;
	}

	// Read the color
	ReadColor (Color, primitiveNode);

	// Autoinit
	ReadBool ("AUTO_INIT", AutoInit, primitiveNode, filename, config);

	// Deletable
	ReadBool ("DELETABLE", Deletable, primitiveNode, filename, config);

	// File extension
	CIXml::getPropertyString (FileExtension, primitiveNode, "FILE_EXTENSION");

	// File type
	CIXml::getPropertyString (FileType, primitiveNode, "FILE_TYPE");

	// Collision
	ReadBool ("COLLISION", Collision, primitiveNode, filename, config);

	// LinkBrothers
	ReadBool ("LINK_BROTHERS", LinkBrothers, primitiveNode, filename, config);

	// ShowArrow
	ReadBool ("SHOW_ARROW", ShowArrow, primitiveNode, filename, config);

	// Numberize when copy the primitive
	ReadBool ("NUMBERIZE", Numberize, primitiveNode, filename, config);

	// Visible ?
	ReadBool ("VISIBLE", Visible, primitiveNode, filename, config);

	// Read the parameters
	for (	xmlNodePtr paramNode = CIXml::getFirstChildNode (primitiveNode, "PARAMETER");
			paramNode != NULL;
			paramNode = CIXml::getNextChildNode (paramNode, "PARAMETER"))
	{
		// Read the property name
		if (!config.getPropertyString (type, filename, paramNode, "NAME"))
			goto failed;

		// look if the parameter is not already defined by the parent class
		uint i=0;
		while (i<Parameters.size())
		{
			if (Parameters[i].Name == type)
			{
				// the param already exist, remove parent param
				Parameters.erase(Parameters.begin() + i);
				continue;
			}
			++i;
		}

		// Add a parameter
		Parameters.push_back (CParameter ());

		// The parameter ref
		CParameter &parameter = Parameters.back ();

		// Set the name
		parameter.Name = type;

		// Read the type
		if (!config.getPropertyString (type, filename, paramNode, "TYPE"))
			goto failed;

		// Good type ?
		if (type == "boolean")
			parameter.Type = CParameter::Boolean;
		else if (type == "const_string")
			parameter.Type = CParameter::ConstString;
		else if (type == "string")
			parameter.Type = CParameter::String;
		else if (type == "string_array")
			parameter.Type = CParameter::StringArray;
		else if (type == "const_string_array")
			parameter.Type = CParameter::ConstStringArray;
		else
		{
			config.syntaxError (filename, paramNode, "Unknown primitive parameter type (%s)", type.c_str ());
			goto failed;
		}

		// Visible
		parameter.Visible = true;
		ReadBool ("VISIBLE", parameter.Visible, paramNode, filename, config);

		// Filename
		parameter.Filename = false;
		ReadBool ("FILENAME", parameter.Filename, paramNode, filename, config);

		// Lookup
		parameter.Lookup = false;
		ReadBool ("LOOKUP", parameter.Lookup, paramNode, filename, config);

		// Read only primitive
		parameter.ReadOnly = false;
		ReadBool ("READ_ONLY", parameter.ReadOnly, paramNode, filename, config);

		// Deletable
		parameter.Editable = false;
		ReadBool ("EDITABLE", parameter.Editable, paramNode, filename, config);

		// sort combo box entries
		parameter.SortEntries = false;
		ReadBool ("SORT_ENTRIES", parameter.SortEntries, paramNode, filename, config);

		// Display horizontal scroller in multi-line edit box
		parameter.DisplayHS = false;
		ReadBool ("SHOW_HS", parameter.DisplayHS, paramNode, filename, config);

		// Lookup
		parameter.WidgetHeight = 100;
		int temp;
		if (ReadInt ("WIDGET_HEIGHT", temp, paramNode))
			parameter.WidgetHeight = (uint)temp;

		// Read the file extension
		parameter.FileExtension = "";
		CIXml::getPropertyString (parameter.FileExtension, paramNode, "FILE_EXTENSION");
		parameter.FileExtension = toLower(parameter.FileExtension);

		// Autonaming preference
		parameter.Autoname = "";
		CIXml::getPropertyString (parameter.Autoname, paramNode, "AUTONAME");

		// Read the file extension
		parameter.Folder = "";
		CIXml::getPropertyString (parameter.Folder, paramNode, "FOLDER");
		parameter.Folder = toLower(parameter.Folder);

		// Read the combo values
		for (	xmlNodePtr comboValueNode = CIXml::getFirstChildNode (paramNode, "COMBO_VALUES");
				comboValueNode != NULL;
				comboValueNode = CIXml::getNextChildNode (comboValueNode, "COMBO_VALUES"))
		{
			// Read the context
			if (!config.getPropertyString (type, filename, comboValueNode, "CONTEXT_NAME"))
				goto failed;

			// Add this context
			contextStrings.insert (type);

			// Add a combo value
			pair<std::map<std::string, CParameter::CConstStringValue>::iterator, bool> insertResult =
				parameter.ComboValues.insert (std::map<std::string, CParameter::CConstStringValue>::value_type (type, CParameter::CConstStringValue ()));

			// The combo value ref
			CParameter::CConstStringValue &comboValue = insertResult.first->second;

			// Read the values
			for (	xmlNodePtr comboValueValueNode = CIXml::getFirstChildNode (comboValueNode, "CONTEXT_VALUE");
					comboValueValueNode != NULL;
					comboValueValueNode = CIXml::getNextChildNode (comboValueValueNode, "CONTEXT_VALUE"))
			{
				// Read the value
				if (!config.getPropertyString (type, filename, comboValueValueNode, "VALUE"))
					goto failed;

				comboValue.Values.push_back (type);
			}
		}

		// Read the combo files
		for (	xmlNodePtr comboValueNode = CIXml::getFirstChildNode (paramNode, "COMBO_FILES");
				comboValueNode != NULL;
				comboValueNode = CIXml::getNextChildNode (comboValueNode, "COMBO_FILES"))
		{
			// Read the context
			if (!config.getPropertyString (type, filename, comboValueNode, "CONTEXT_NAME"))
				goto failed;

			// Read the path to search
			string path;
			if	(CIXml::getPropertyString (path, comboValueNode, "PATH"))
			{
				if (!parsePrimitiveComboContent)
					continue;

				// Look for files in the path
				std::vector<std::string> files;
				CPath::getPathContent (path, true, false, true, files);

				// Not empty ?
				if (files.empty ())
					continue;

				// Add this context
				contextStrings.insert (type);

				// For each file
				for (uint i=0; i<files.size (); i++)
				{
					// Good extension ?
					if (toLower(NLMISC::CFile::getExtension (files[i])) != parameter.FileExtension)
						continue;

					// Add a combo value
					pair<std::map<std::string, CParameter::CConstStringValue>::iterator, bool> insertResult =
						parameter.ComboValues.insert (std::map<std::string, CParameter::CConstStringValue>::value_type (type, CParameter::CConstStringValue ()));

					// The combo value ref
					CParameter::CConstStringValue &comboValue = insertResult.first->second;

					// Get the filename without extension
					string nameWithoutExt = toLower(NLMISC::CFile::getFilenameWithoutExtension (files[i]));

					// Add the values
					comboValue.Values.push_back (nameWithoutExt);

					// Add the value for lookup
					contextFilesLookup.insert (map<string, string>::value_type (nameWithoutExt, files[i]));
				}
			}
			else
			{
				string	primpath;
				if	(!config.getPropertyString (primpath, filename, comboValueNode, "PRIM_PATH"))
					goto failed;

				// Add this context
				contextStrings.insert (type);

				// Add a combo value
				pair<std::map<std::string, CParameter::CConstStringValue>::iterator, bool> insertResult =
					parameter.ComboValues.insert (std::map<std::string, CParameter::CConstStringValue>::value_type (type, CParameter::CConstStringValue ()));

				// The combo value ref
				CParameter::CConstStringValue &comboValue = insertResult.first->second;

				comboValue.PrimitivePath.push_back(primpath);
			}
		}

		// Read parameters default values
		uint defaultId = 0;
		parameter.DefaultValue.resize (CIXml::countChildren (paramNode, "DEFAULT_VALUE"));
		for (	xmlNodePtr defaultValueNode = CIXml::getFirstChildNode (paramNode, "DEFAULT_VALUE");
				defaultValueNode != NULL;
				defaultValueNode = CIXml::getNextChildNode (defaultValueNode, "DEFAULT_VALUE"))
		{
			// Gen id flag
			parameter.DefaultValue[defaultId].GenID = false;

			// Read the gen id flag
			string value;
			if (CIXml::getPropertyString (value, defaultValueNode, "GEN_ID") && (value != "false"))
			{
				parameter.DefaultValue[defaultId].GenID = true;
			}
			else
			{
				if (!config.getPropertyString (value, filename, defaultValueNode, "VALUE"))
					goto failed;
				parameter.DefaultValue[defaultId].Name = value;
			}
			defaultId++;
		}
	}

	// Read static children
	StaticChildren.reserve (StaticChildren.size() + CIXml::countChildren (primitiveNode, "STATIC_CHILD"));
	for (	xmlNodePtr childrenNode = CIXml::getFirstChildNode (primitiveNode, "STATIC_CHILD");
			childrenNode != NULL;
			childrenNode = CIXml::getNextChildNode (childrenNode, "STATIC_CHILD"))
	{
		// Add a static child
		StaticChildren.push_back (CChild ());

		// Child ref
		CChild &child = StaticChildren.back ();

		// Read the child
		if (!ReadChild (child, childrenNode, filename, true, config))
			goto failed;
	}

	// Read dynamic children
	DynamicChildren.reserve (DynamicChildren.size() + CIXml::countChildren (primitiveNode, "DYNAMIC_CHILD"));
	for (	xmlNodePtr childrenNode = CIXml::getFirstChildNode (primitiveNode, "DYNAMIC_CHILD");
			childrenNode != NULL;
			childrenNode = CIXml::getNextChildNode (childrenNode, "DYNAMIC_CHILD"))
	{
		// Add a static child
		DynamicChildren.push_back (CChild ());

		// Child ref
		CChild &child = DynamicChildren.back ();

		// Read the child
		if (!ReadChild (child, childrenNode, filename, false, config))
			goto failed;
	}

	// Read generated children
	GeneratedChildren.reserve (GeneratedChildren.size() + CIXml::countChildren (primitiveNode, "GENERATED_CHILD"));
	for (	xmlNodePtr childrenNode = CIXml::getFirstChildNode (primitiveNode, "GENERATED_CHILD");
			childrenNode != NULL;
			childrenNode = CIXml::getNextChildNode (childrenNode, "GENERATED_CHILD"))
	{
		// Add a static child
		GeneratedChildren.push_back (CChild ());

		// Child ref
		CChild &child = GeneratedChildren.back ();

		// Read the child
		if (!ReadChild (child, childrenNode, filename, false, config))
			goto failed;
	}

	return true;
failed:
	return false;
}
Esempio n. 5
0
int extractBotNames(int argc, char *argv[])
{
	//-------------------------------------------------------------------
	// read the parameters
	for (int i=2; i<argc; ++i)
	{
		string s = argv[i];
		if (s == "-r")
		{
			// active remove mode
			RemoveOlds = true;
		}
		else
		{
			nlwarning("Unknow option '%s'", argv[i]);
			return -1;
		}
	}

	//-------------------------------------------------------------------
	// read the configuration file
	CConfigFile	cf;

	cf.load("bin/translation_tools.cfg");

	//-------------------------------------------------------------------
	// read the vars
	CConfigFile::CVar &paths = cf.getVar("Paths");
	CConfigFile::CVar &filtersVar = cf.getVar("Filters");
	CConfigFile::CVar &ligoClassFile= cf.getVar("LigoClassFile");
	CConfigFile::CVar &georgesPaths= cf.getVar("GeorgesPaths");
	CConfigFile::CVar &pathNoRecurse= cf.getVar("PathsNoRecurse");
	CConfigFile::CVar &workBotNamesFile= cf.getVar("WorkBotNamesFile");
	CConfigFile::CVar &transBotNamesFile= cf.getVar("TransBotNamesFile");
	CConfigFile::CVar &workTitleFile= cf.getVar("WorkTitleFile");

	for (uint i=0; i<paths.size(); ++i)
	{
		CPath::addSearchPath(paths.asString(i), true, false);
	}
	for (uint i=0; i<pathNoRecurse.size(); ++i)
	{
		CPath::addSearchPath(pathNoRecurse.asString(i), false, false);
	}

	for (uint i=0; i<filtersVar.size(); ++i)
	{
		Filters.push_back(filtersVar.asString(i));
	}


	//-------------------------------------------------------------------
	// init the sheets
	CSheetId::init(false);
	const string PACKED_SHEETS_NAME = "bin/translation_tools_creature.packed_sheets";
	loadForm("creature", PACKED_SHEETS_NAME, Creatures, false, false);

	if (Creatures.empty())
	{
		for (uint i=0;i<georgesPaths.size();++i)
			CPath::addSearchPath(georgesPaths.asString(i).c_str(), true, false);

		loadForm("creature", PACKED_SHEETS_NAME, Creatures, true);
	}


	//-------------------------------------------------------------------
	// init ligo config
	string ligoPath = CPath::lookup(ligoClassFile.asString(), true, true);
	LigoConfig.readPrimitiveClass(ligoPath.c_str(), false);
	NLLIGO::Register();

	CPrimitiveContext::instance().CurrentLigoConfig = &LigoConfig;

	//-------------------------------------------------------------------
	// ok, ready the the real work,
	// first, read the primitives files and parse the primitives
	vector<string>	files;
	CPath::getFileList("primitive", files);

	for (uint i=0; i<files.size(); ++i)
	{
		string pathName = files[i];
		pathName = CPath::lookup(pathName);

		// check filters
		uint j=0;
		for (j=0; j<Filters.size(); ++j)
		{
			if (pathName.find(Filters[j]) != string::npos)
				break;
		}
		if (j != Filters.size())
			// skip this file
			continue;

		nlinfo("Loading file '%s'...", CFile::getFilename(pathName).c_str());
		
		CPrimitives primDoc;
		CPrimitiveContext::instance().CurrentPrimitive = &primDoc;
		loadXmlPrimitiveFile(primDoc, pathName, LigoConfig);

		// now parse the file

		// look for group template
		{
			TPrimitiveClassPredicate pred("group_template_npc");
			TPrimitiveSet result;

			CPrimitiveSet<TPrimitiveClassPredicate> ps;
			ps.buildSet(primDoc.RootNode, pred, result);

			for (uint i=0; i<result.size(); ++i)
			{
				string name;
				string countStr;
				string sheetStr;
				result[i]->getPropertyByName("name", name);
				result[i]->getPropertyByName("count", countStr);
				result[i]->getPropertyByName("bot_sheet_look", sheetStr);

				uint32 count;
				NLMISC::fromString(countStr, count);

				if (count != 0)
				{
					if (sheetStr.empty())
					{
						nlwarning("In '%s', empty sheet !", buildPrimPath(result[i]).c_str());
					}
					else
					{
						addGenericName(removeAndStoreFunction(name), sheetStr);
					}
				}
			}
		}
		// look for bot template
		{
			TPrimitiveClassPredicate pred("bot_template_npc");
			TPrimitiveSet result;

			CPrimitiveSet<TPrimitiveClassPredicate> ps;
			ps.buildSet(primDoc.RootNode, pred, result);

			for (uint i=0; i<result.size(); ++i)
			{
				string name;
				string sheetStr;
				result[i]->getPropertyByName("name", name);
				result[i]->getPropertyByName("sheet_look", sheetStr);

				if (sheetStr.empty())
				{
					// take the sheet in the parent
					result[i]->getParent()->getPropertyByName("bot_sheet_look", sheetStr);
				}

				if (sheetStr.empty())
				{
					nlwarning("In '%s', empty sheet !", buildPrimPath(result[i]).c_str());
				}
				else
				{
					addGenericName(removeAndStoreFunction(name), sheetStr);
				}
			}
		}
		// look for npc_group 
		{
			TPrimitiveClassPredicate pred("npc_group");
			TPrimitiveSet result;

			CPrimitiveSet<TPrimitiveClassPredicate> ps;
			ps.buildSet(primDoc.RootNode, pred, result);

			for (uint i=0; i<result.size(); ++i)
			{
				string name;
				string countStr;
				string sheetStr;
				result[i]->getPropertyByName("name", name);
				result[i]->getPropertyByName("count", countStr);
				result[i]->getPropertyByName("bot_sheet_client", sheetStr);

				uint32 count;
				NLMISC::fromString(countStr, count);

				if (count > 0 && sheetStr.empty())
				{
					nlwarning("In '%s', empty sheet !", buildPrimPath(result[i]).c_str());
				}
				else
				{
					if (count == 1)
					{
						addSimpleName(removeAndStoreFunction(name), sheetStr);
					}
					else if (count > 1)
					{
						addGenericName(removeAndStoreFunction(name), sheetStr);
					}
				}
			}
		}
		// look for bot 
		{
			TPrimitiveClassPredicate pred("npc_bot");
			TPrimitiveSet result;

			CPrimitiveSet<TPrimitiveClassPredicate> ps;
			ps.buildSet(primDoc.RootNode, pred, result);

			for (uint i=0; i<result.size(); ++i)
			{
				string name;
				string sheetStr;
				result[i]->getPropertyByName("name", name);
				result[i]->getPropertyByName("sheet_client", sheetStr);

				if (sheetStr.empty())
				{
					// take the sheet in the parent
					result[i]->getParent()->getPropertyByName("bot_sheet_client", sheetStr);
				}

				if (sheetStr.empty())
				{
					nlwarning("In '%s', empty sheet !", buildPrimPath(result[i]).c_str());
				}
				else
				{
					TEntryInfo ei;
					addSimpleName(removeAndStoreFunction(name), sheetStr);
				}
			}
		}
	}

	//-------------------------------------------------------------------
	// step 2 : load the reference file

	nlinfo("Looking for missing translation:");

	TWorksheet			botNames;
	loadExcelSheet(workBotNamesFile.asString(), botNames, true);
	TWorksheet			transBotNames;
	loadExcelSheet(transBotNamesFile.asString(), transBotNames, true);

	TWorksheet			fcts;
	loadExcelSheet(workTitleFile.asString(), fcts, true);


	// add missing element

	uint	nbAddSimpleName = 0;
	uint	nbAddFunction = 0;
	uint	nbAddGenericName = 0;

	uint botIdCol;
	nlverify(botNames.findId(botIdCol));
	uint transIdCol;
	nlverify(transBotNames.findId(transIdCol));
	uint	fctsIdCol;
	nlverify(fcts.findId(fctsIdCol));

	// special treatment to add the sheet_name col
	{
		uint sheetCol;
		if (!botNames.findCol(ucstring("sheet_name"), sheetCol))
		{
			botNames.insertColumn(botNames.ColCount);
			botNames.setData(0, botNames.ColCount-1, ucstring("sheet_name"));
		}
		
		if (!transBotNames.findCol(ucstring("sheet_name"), sheetCol))
		{
			transBotNames.insertColumn(transBotNames.ColCount);
			transBotNames.setData(0, transBotNames.ColCount-1, ucstring("sheet_name"));
		}
	}
	// 1 - simple names
	{
		nlinfo("  Simple names...");


		map<string, TEntryInfo>::iterator first(SimpleNames.begin()), last(SimpleNames.end());
		for (; first != last; ++first)
		{
			uint rowIdx;
			if (!botNames.findRow(botIdCol, first->first, rowIdx))
			{
				// we need to add the entry
				rowIdx = botNames.size();
				botNames.resize(botNames.size()+1);

				botNames.setData(rowIdx, ucstring("bot name"), first->first);
				botNames.setData(rowIdx, ucstring("translated name"), first->first);
				botNames.setData(rowIdx, ucstring("sheet_name"), first->second.SheetName);

				nbAddSimpleName++;
			}
			else
			{
				// set/update the sheet name info
				// try to restore the existing translation
				uint transRowIdx;
				if (transBotNames.findRow(transIdCol, first->first, transRowIdx))
				{
					ucstring wkBotName = botNames.getData(rowIdx, ucstring("bot name"));
					ucstring wkSheetName = botNames.getData(rowIdx, ucstring("sheet_name"));								
					ucstring wkTranslationName = botNames.getData(rowIdx, ucstring("translated name"));
					ucstring ucWkHash;
					uint64 hash = CI18N::makeHash(wkBotName + wkTranslationName +wkSheetName);						
					CI18N::hashToUCString(hash, ucWkHash);
					ucstring trUcHash = transBotNames[transRowIdx][0];
					bool isWkTranslationNameAGroupName = wkTranslationName.find(ucstring("$")) != ucstring::npos;
					bool hashIsValide = std::equal(ucWkHash.begin(), ucWkHash.end(), trUcHash.begin()+1);
					// Hash is equal get the translation
					if (hashIsValide && !isWkTranslationNameAGroupName)
					{
						wkTranslationName = transBotNames.getData(transRowIdx, ucstring("translated name"));
						wkSheetName = transBotNames.getData(transRowIdx, ucstring("sheet_name"));
						botNames.setData(rowIdx, ucstring("translated name"), wkTranslationName);
						botNames.setData(rowIdx, ucstring("sheet_name"), wkSheetName);
						hash = CI18N::makeHash(wkBotName + wkTranslationName + wkSheetName);						
  						// update the hash code
						CI18N::hashToUCString(hash, transBotNames[transRowIdx][0]);							
					}
					// bots_name.txt has been manually changed. We trust what the Level Designer has done. We don't destroy is work.
					// or it is a simple 
					else
					{
						//use the "translated name" of the manually changed  work/bot_name.txt
						botNames.setData(rowIdx, ucstring("translated name"), wkTranslationName);
						botNames.setData(rowIdx, ucstring("sheet_name"), wkSheetName);	
					}					
				}
			}
		}
	}

	// 2 - generic names
	
	{
		nlinfo("  Generic names...");

		set<string>::iterator first(GenericNames.begin()), last(GenericNames.end());
		for (; first != last; ++first)
		{
			string gnName = "gn_" + cleanupName(*first);

			ucstring fctsTitleId;
			ucstring fctsName;
			// add or modify the bot names
			uint rowIdx;
			if (!botNames.findRow(botIdCol, *first, rowIdx)) 
			{
				// we need to add the entry
				rowIdx = botNames.size();
				botNames.resize(botNames.size()+1);

				botNames.setData(rowIdx, ucstring("bot name"), *first);
				botNames.setData(rowIdx, ucstring("translated name"), ucstring("$") + gnName + "$");
				botNames.setData(rowIdx, ucstring("sheet_name"), ucstring());
				fctsTitleId = gnName;
				fctsName = *first;

				nbAddSimpleName++;
			}
			else
			{
				// look in the translated table to remember the translated name to write it in the string file
				ucstring wkBotName = botNames.getData(rowIdx, ucstring("bot name"));				
				ucstring wkTranslationName = botNames.getData(rowIdx, ucstring("translated name"));
				ucstring wkSheetName = botNames.getData(rowIdx, ucstring("sheet_name"));

				
				nlinfo("Bot name:%s\n",wkBotName.toString().c_str());
				bool isWkTranslationNameAGroupName = wkTranslationName.find(ucstring("$")) != ucstring::npos;
				
				if ( isWkTranslationNameAGroupName ) //work name looks like "$gn_***$: do not modify
				{

					//Do not change work/bot_name.txt
					// update work/world_title.txt

					ucstring transName;
					fctsTitleId = makeGroupName(wkTranslationName);
					uint transRowIdx;
					if (transBotNames.findRow(transIdCol, *first, transRowIdx))
					{
						transName = transBotNames.getData(transRowIdx, ucstring("translated name"));

						if (transName.find(ucstring("$")) != ucstring::npos)
						{
							transName = fctsTitleId;
						} 
						
					}
					else
					{
						transName = fctsTitleId;
					}
					//Do not touch anything
					botNames.setData(rowIdx, ucstring("translated name"), wkTranslationName);
					botNames.setData(rowIdx, ucstring("sheet_name"), wkSheetName); 
					// fctsTitleId = makeGroupName(wkTranslationName);
					fctsName = transName;

				}
				else // WkTranslationName != "$gn*$"
				{
						uint transRowIdx;
						ucstring transName;
						ucstring wkSheetName;
						// Get the translation as a simple name.
						if (transBotNames.findRow(transIdCol, *first, transRowIdx))
						{
		
							transName = transBotNames.getData(transRowIdx, ucstring("translated name"));
							ucstring trSheetName = transBotNames.getData(transRowIdx, ucstring("sheet_name"));

							//tr."translation name" is 
							if (transName.find(ucstring("$")) != ucstring::npos)
							{
								//get Translation, update hash
								botNames[rowIdx][1] = transName;
								botNames[rowIdx][2] = trSheetName;		
								fctsTitleId = makeGroupName(transName);
								fctsName = makeGroupName(transName);
								ucstring trNewUcHash;
								uint64 hash = CI18N::makeHash(wkBotName + transName +trSheetName);						
								CI18N::hashToUCString(hash, trNewUcHash);
								transBotNames[transRowIdx][0] = ucstring("_") + trNewUcHash;
							}
							else //botNames."translated name" != $gn_$ && tansName."translated name" != $gn_$
							{

								// get the translation back
								//update work/bot_name.txt
								wkTranslationName = ucstring("$")+gnName+"$";
								botNames[rowIdx][0] = wkBotName;
								botNames[rowIdx][1] = wkTranslationName;
								botNames[rowIdx][2] = wkSheetName;		
									
									//update translated/bot_name.txt

								fctsName = transName;	//transName	
								fctsTitleId = gnName;
								ucstring trNewUcHash;
								uint64 hash = CI18N::makeHash(botNames[rowIdx][0] + botNames[rowIdx][1] +botNames[rowIdx][2]);						
								CI18N::hashToUCString(hash, trNewUcHash);
								transBotNames[transRowIdx][0] = ucstring("_") + trNewUcHash;
							}

						}
						else //There is no translation yet
						{
								fctsName = wkTranslationName;
								wkTranslationName = ucstring("$")+gnName+"$";
								botNames[rowIdx][0] = wkBotName;
								botNames[rowIdx][1] = wkTranslationName;
								botNames[rowIdx][2] = wkSheetName;		
								fctsTitleId = gnName;

				
						}				
				}

			}


			// look for a corresponding entry
			uint gnNameRow;


			if (!fcts.findRow(fctsIdCol, fctsTitleId, gnNameRow))
			{
				
				// not found, add it
				gnNameRow = fcts.size();
				fcts.resize(fcts.size()+1);
				fcts.setData(gnNameRow, ucstring("title_id"), fctsTitleId);
				fcts.setData(gnNameRow, ucstring("name"), fctsName);										
				nbAddGenericName++;
				
			}
			else //Update 
			{
			
			}
		}
	}


	// 3 - functions
	{
		nlinfo("  Functions...");

		set<string>::iterator first(Functions.begin()), last(Functions.end());
		for (; first != last; ++first)
		{
			string fctName = *first;
			// look for a corresponding entry
			uint functionRow;
			if (!fcts.findRow(fctsIdCol, fctName, functionRow))
			{
				// not found, add it
				functionRow = fcts.size();
				fcts.resize(fcts.size()+1);

				fcts.setData(functionRow, ucstring("title_id"), fctName);
				fcts.setData(functionRow, ucstring("name"), *first);

				nbAddFunction++;
			}
		}
	}

	// display resumé
	nlinfo("Adding %u new simple name", nbAddSimpleName);
	nlinfo("Adding %u new generic name", nbAddGenericName);
	nlinfo("Adding %u new function name", nbAddFunction);

	// saving the modified files

	ucstring s = prepareExcelSheet(botNames);
	CI18N::writeTextFile(workBotNamesFile.asString(), s, false);
	s = prepareExcelSheet(transBotNames);
	CI18N::writeTextFile(transBotNamesFile.asString(), s, false);
	s = prepareExcelSheet(fcts);
	CI18N::writeTextFile(workTitleFile.asString(), s, false);

	return 0;
}
// ***************************************************************************
int extractNewSheetNames(int argc, char *argv[])
{
	// **** read the parameters
	for (int i=2; i<argc; ++i)
	{
		string s = argv[i];
		if (s == "-r")
		{
			// active remove mode
			RemoveOlds = true;
		}
		else
		{
			nlwarning("Unknow option '%s'", argv[i]);
			return -1;
		}
	}
	
	// **** avoid some flood
	NLMISC::createDebug();
	NLMISC::DebugLog->addNegativeFilter("numCol changed to");
	NLMISC::InfoLog->addNegativeFilter("CPath::addSearchPath");
	

	// **** read the configuration file
	CConfigFile	cf;
	cf.load("bin/translation_tools.cfg");
	CConfigFile::CVar &paths = cf.getVar("Paths");
	CConfigFile::CVar &pathNoRecurse= cf.getVar("PathsNoRecurse");
	CConfigFile::CVar &ligoClassFile= cf.getVar("LigoClassFile");

	// parse path
	for (uint i=0; i<paths.size(); ++i)
	{
		CPath::addSearchPath(paths.asString(i), true, false);
	}
	for (uint i=0; i<pathNoRecurse.size(); ++i)
	{
		CPath::addSearchPath(pathNoRecurse.asString(i), false, false);
	}
	
	// init ligo config once
	string ligoPath = CPath::lookup(ligoClassFile.asString(), true, true);
	LigoConfig.readPrimitiveClass(ligoPath.c_str(), false);
	NLLIGO::Register();
	CPrimitiveContext::instance().CurrentLigoConfig = &LigoConfig;
	
	
	
	// **** Parse all the different type of sheets
	const char	*sheetDefs[]=
	{
		// 1st is the name of the worksheet file. 
		// 2nd is the Key column identifier. 
		// 3rd is the sheet extension
		// 4th is the directory where to find new sheets
		"work/item_words_wk.txt",		"item ID",		"sitem",		"l:/leveldesign/game_element/sitem",
		"work/creature_words_wk.txt",	"creature ID",	"creature",		"l:/leveldesign/game_elem/creature/fauna",	// take fauna only because other are special
		"work/sbrick_words_wk.txt",		"sbrick ID",	"sbrick",		"l:/leveldesign/game_element/sbrick",
		"work/sphrase_words_wk.txt",	"sphrase ID",	"sphrase",		"l:/leveldesign/game_element/sphrase",
	};
	uint	numSheetDefs= sizeof(sheetDefs) / (4*sizeof(sheetDefs[0]));
	
	// For all different type of sheet
	for(uint i=0;i<numSheetDefs;i++)
	{
		CSheetWordListBuilder	builder;
		builder.SheetExt= sheetDefs[i*4+2];
		builder.SheetPath= sheetDefs[i*4+3];
		extractNewWords(sheetDefs[i*4+0], sheetDefs[i*4+1], builder);
	}


	// **** Parse place and region names
	{
		// build place names
		CRegionPrimWordListBuilder	builder;
		builder.PrimPath= "l:/primitives";
		builder.PrimFilter.push_back("region_*.primitive");
		builder.PrimFilter.push_back("indoors_*.primitive");
		extractNewWords("work/place_words_wk.txt", "placeId", builder);
	}


	return 0;
}