From 2273376dffb80af0cbf1bc1d8cc8990e1d1456f3 Mon Sep 17 00:00:00 2001
From: Steven Bennetts <steve@lindenlab.com>
Date: Fri, 4 Sep 2009 00:16:51 +0000
Subject: DEV-39441 - Eliminate boost:regexp from LLString::format Also removed
 a missing setting (merge bug)

---
 indra/llcommon/lldate.cpp   |  10 +-
 indra/llcommon/llstring.cpp | 319 +++++++++++++++++++++++++++++++++++++++++++-
 indra/llcommon/llstring.h   | 301 +----------------------------------------
 3 files changed, 328 insertions(+), 302 deletions(-)

(limited to 'indra/llcommon')

diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp
index 7bc9e16bc9..6a82a848be 100644
--- a/indra/llcommon/lldate.cpp
+++ b/indra/llcommon/lldate.cpp
@@ -94,8 +94,12 @@ std::string LLDate::asRFC1123() const
 	return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT"));
 }
 
+LLFastTimer::DeclareTimer FT_DATE_FORMAT("Date Format");
+
 std::string LLDate::toHTTPDateString (std::string fmt) const
 {
+	LLFastTimer ft1(FT_DATE_FORMAT);
+	
 	std::ostringstream stream;
 	time_t locSeconds = (time_t) mSecondsSinceEpoch;
 	struct tm * gmt = gmtime (&locSeconds);
@@ -107,6 +111,8 @@ std::string LLDate::toHTTPDateString (std::string fmt) const
 
 std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt)
 {
+	LLFastTimer ft1(FT_DATE_FORMAT);
+	
 	std::ostringstream stream;
 	stream.imbue (std::locale(LLStringUtil::getLocale().c_str()));
 	toHTTPDateStream (stream, gmt, fmt);
@@ -115,11 +121,11 @@ std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt)
 
 void LLDate::toHTTPDateStream(std::ostream& s, tm * gmt, std::string fmt)
 {
-	using namespace std;
+	LLFastTimer ft1(FT_DATE_FORMAT);
 
 	const char * pBeg = fmt.c_str();
 	const char * pEnd = pBeg + fmt.length();
-	const time_put<char>& tp = use_facet<time_put<char> >(s.getloc());
+	const std::time_put<char>& tp = std::use_facet<std::time_put<char> >(s.getloc());
 	tp.put (s, s, s.fill(), gmt, pBeg, pEnd);
 }
 
diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index d7da40d645..16cfb2fc25 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -42,7 +42,7 @@
 #include <winnls.h> // for WideCharToMultiByte
 #endif
 
-LLFastTimer::DeclareTimer STRING_LOCALIZATION("String Localization");
+LLFastTimer::DeclareTimer FT_STRING_FORMAT("String Format");
 
 
 std::string ll_safe_string(const char* in)
@@ -776,12 +776,12 @@ namespace LLStringFn
 	// https://wiki.lindenlab.com/wiki/Unicode_Guidelines has details on
 	// allowable code points for XML. Specifically, they are:
 	// 0x09, 0x0a, 0x0d, and 0x20 on up.  JC
-	std::string strip_invalid_xml(const std::string& input)
+	std::string strip_invalid_xml(const std::string& instr)
 	{
 		std::string output;
-		output.reserve( input.size() );
-		std::string::const_iterator it = input.begin();
-		while (it != input.end())
+		output.reserve( instr.size() );
+		std::string::const_iterator it = instr.begin();
+		while (it != instr.end())
 		{
 			// Must compare as unsigned for >=
 			// Test most likely match first
@@ -817,6 +817,315 @@ namespace LLStringFn
 	}
 }
 
+////////////////////////////////////////////////////////////
+
+//static
+template<> 
+void LLStringUtil::getTokens(const std::string& instr, std::vector<std::string >& tokens, const std::string& delims)
+{
+	std::string currToken;
+	std::string::size_type begIdx, endIdx;
+
+	begIdx = instr.find_first_not_of (delims);
+	while (begIdx != std::string::npos)
+	{
+		endIdx = instr.find_first_of (delims, begIdx);
+		if (endIdx == std::string::npos)
+		{
+			endIdx = instr.length();
+		}
+
+		currToken = instr.substr(begIdx, endIdx - begIdx);
+		LLStringUtil::trim (currToken);
+		tokens.push_back(currToken);
+		begIdx = instr.find_first_not_of (delims, endIdx);
+	}
+}
+
+template<> 
+LLStringUtil::size_type LLStringUtil::getSubstitution(const std::string& instr, size_type& start, std::vector<std::string>& tokens)
+{
+	const std::string delims (",");
+	
+	// Find the first ]
+	size_type pos2 = instr.find(']', start);
+	if (pos2 == std::string::npos)
+		return std::string::npos;
+
+	// Find the last [ before ]
+	size_type pos1 = instr.find_last_of('[', pos2-1);
+	if (pos1 == std::string::npos || pos1 < start)
+		return std::string::npos;
+	
+	getTokens(std::string(instr,pos1+1,pos2-pos1-1), tokens, delims);
+	start = pos2+1;
+	
+	return pos1;
+}
+
+// LLStringUtil::format recogizes the following patterns.
+// All substitutions *must* be encased in []'s in the input string.
+// The []'s are optional in the substitution map.
+// [FOO_123]
+// [FOO,number,precision]
+// [FOO,datetime,format]
+
+
+// static
+template<> 
+S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
+{
+	LLFastTimer ft(FT_STRING_FORMAT);
+	S32 res = 0;
+
+	std::string output;
+	std::vector<std::string> tokens;
+
+	std::string::size_type start = 0;
+	std::string::size_type prev_start = 0;
+	std::string::size_type key_start = 0;
+	while ((key_start = getSubstitution(s, start, tokens)) != std::string::npos)
+	{
+		output += std::string(s, prev_start, key_start-prev_start);
+		prev_start = start;
+		
+		bool found_replacement = false;
+		std::string replacement;
+
+		if (tokens.size() == 1)
+		{
+			found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
+		}
+		else if (tokens[1] == "number")
+		{
+			std::string param = "0";
+
+			if (tokens.size() > 2) param = tokens[2];
+			found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
+			if (found_replacement) formatNumber (replacement, param);
+		}
+		else if (tokens[1] == "datetime")
+		{
+			std::string param;
+			if (tokens.size() > 2) param = tokens[2];
+			
+			format_map_t::const_iterator iter = substitutions.find("datetime");
+			if (iter != substitutions.end())
+			{
+				S32 secFromEpoch = 0;
+				BOOL r = LLStringUtil::convertToS32(iter->second, secFromEpoch);
+				if (r)
+				{
+					found_replacement = formatDatetime(replacement, tokens[0], param, secFromEpoch);
+				}
+			}
+		}
+
+		if (found_replacement)
+		{
+			output += replacement;
+			res++;
+		}
+		else
+		{
+			// we had no replacement, so leave the string we searched for so that it gets noticed by QA
+			// "hello [NAME_NOT_FOUND]" is output
+			output += std::string("[") + tokens[0] + std::string("]");
+		}
+		tokens.clear();
+	}
+	// send the remainder of the string (with no further matches for bracketed names)
+	output += std::string(s, start);
+	s = output;
+	return res;
+}
+
+//static
+template<> 
+S32 LLStringUtil::format(std::string& s, const LLSD& substitutions)
+{
+	LLFastTimer ft(FT_STRING_FORMAT);
+	S32 res = 0;
+
+	if (!substitutions.isMap()) 
+	{
+		return res;
+	}
+
+	std::string output;
+	std::vector<std::string> tokens;
+
+	std::string::size_type start = 0;
+	std::string::size_type prev_start = 0;
+	std::string::size_type key_start = 0;
+	while ((key_start = getSubstitution(s, start, tokens)) != std::string::npos)
+	{
+		output += std::string(s, prev_start, key_start-prev_start);
+		prev_start = start;
+		
+		bool found_replacement = false;
+		std::string replacement;
+
+		if (tokens.size() == 1)
+		{
+			found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
+		}
+		else if (tokens[1] == "number")
+		{
+			std::string param = "0";
+
+			if (tokens.size() > 2) param = tokens[2];
+			found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
+			if (found_replacement) formatNumber (replacement, param);
+		}
+		else if (tokens[1] == "datetime")
+		{
+			std::string param;
+			if (tokens.size() > 2) param = tokens[2];
+			
+			S32 secFromEpoch = (S32) substitutions["datetime"].asInteger();
+			found_replacement = formatDatetime (replacement, tokens[0], param, secFromEpoch);
+		}
+
+		if (found_replacement)
+		{
+			output += replacement;
+			res++;
+		}
+		else
+		{
+			// we had no replacement, so leave the string we searched for so that it gets noticed by QA
+			// "hello [NAME_NOT_FOUND]" is output
+			output += std::string("[") + tokens[0] + std::string("]");
+		}
+		tokens.clear();
+	}
+	// send the remainder of the string (with no further matches for bracketed names)
+	output += std::string(s, start);
+	s = output;
+	return res;
+}
+
+// static
+template<> 
+bool LLStringUtil::simpleReplacement(std::string &replacement, std::string token, const format_map_t& substitutions)
+{
+	// see if we have a replacement for the bracketed string (without the brackets)
+	// test first using has() because if we just look up with operator[] we get back an
+	// empty string even if the value is missing. We want to distinguish between 
+	// missing replacements and deliberately empty replacement strings.
+	format_map_t::const_iterator iter = substitutions.find(token);
+	if (iter != substitutions.end())
+	{
+		replacement = iter->second;
+		return true;
+	}
+	// if not, see if there's one WITH brackets
+	iter = substitutions.find(std::string("[" + token + "]"));
+	if (iter != substitutions.end())
+	{
+		replacement = iter->second;
+		return true;
+	}
+
+	return false;
+}
+
+// static
+template<> 
+bool LLStringUtil::simpleReplacement(std::string &replacement, std::string token, const LLSD& substitutions)
+{
+	// see if we have a replacement for the bracketed string (without the brackets)
+	// test first using has() because if we just look up with operator[] we get back an
+	// empty string even if the value is missing. We want to distinguish between 
+	// missing replacements and deliberately empty replacement strings.
+	if (substitutions.has(token))
+	{
+		replacement = substitutions[token].asString();
+		return true;
+	}
+	// if not, see if there's one WITH brackets
+	else if (substitutions.has(std::string("[" + token + "]")))
+	{
+		replacement = substitutions[std::string("[" + token + "]")].asString();
+		return true;
+	}
+
+	return false;
+}
+
+// static
+template<> 
+void LLStringUtil::formatNumber(std::string& numStr, std::string decimals)
+{
+	std::stringstream strStream;
+	S32 intDecimals = 0;
+
+	convertToS32 (decimals, intDecimals);
+	if (!sLocale.empty())
+	{
+		strStream.imbue (std::locale(sLocale.c_str()));
+	}
+
+	if (!intDecimals)
+	{
+		S32 intStr;
+
+		if (convertToS32(numStr, intStr))
+		{
+			strStream << intStr;
+			numStr = strStream.str();
+		}
+	}
+	else
+	{
+		F32 floatStr;
+
+		if (convertToF32(numStr, floatStr))
+		{
+			strStream << std::fixed << std::showpoint << std::setprecision(intDecimals) << floatStr;
+			numStr = strStream.str();
+		}
+	}
+}
+
+// static
+template<> 
+bool LLStringUtil::formatDatetime(std::string& replacement, std::string token,
+								  std::string param, S32 secFromEpoch)
+{
+	if (param == "local")   // local
+	{
+		secFromEpoch -= LLStringOps::getLocalTimeOffset();
+	}
+	else if (param != "utc") // slt
+	{
+		secFromEpoch -= LLStringOps::getSltOffset();
+	}
+		
+	// if never fell into those two ifs above, param must be utc
+	if (secFromEpoch < 0) secFromEpoch = 0;
+
+	LLDate * datetime = new LLDate((F64)secFromEpoch);
+	std::string code = LLStringOps::getDatetimeCode (token);
+
+	// special case to handle timezone
+	if (code == "%Z") {
+		if (param == "utc") replacement = "GMT";
+		else if (param != "local") replacement = LLStringOps::getDaylightSavings()? "PDT" : "PST";
+		return true;
+	}
+	replacement = datetime->toHTTPDateString(code);
+
+	if (code.empty())
+	{
+		return false;
+	}
+	else
+	{
+		return true;
+	}
+}
 
 ////////////////////////////////////////////////////////////
 // Testing
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index c6dcdd6d12..3b1379c76a 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -231,7 +231,8 @@ public:
 	static std::basic_string<T> null;
 	
 	typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t;
-	static void getTokens (std::basic_string<T> input, std::vector<std::basic_string<T> >& tokens);
+	static void getTokens(const std::basic_string<T>& instr, std::vector<std::basic_string<T> >& tokens, const std::basic_string<T>& delims);
+	static size_type getSubstitution(const std::basic_string<T>& instr, size_type& start, std::vector<std::basic_string<T> >& tokens);
 	static void formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals);
 	static bool formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, std::basic_string<T> param, S32 secFromEpoch);
 	static S32 format(std::basic_string<T>& s, const format_map_t& substitutions);
@@ -597,302 +598,12 @@ namespace LLStringFn
 }
 
 ////////////////////////////////////////////////////////////
+// NOTE: LLStringUtil::format, getTokens, and support functions moved to llstring.cpp.
+// There is no LLWStringUtil::format implementation currently.
+// Calling thse for anything other than LLStringUtil will produce link errors.
 
-//static
-template<class T>
-void LLStringUtilBase<T>::getTokens (std::basic_string<T> input, std::vector<std::basic_string<T> >& tokens)
-{
-	const std::basic_string<T> delims (",");
-	std::basic_string<T> currToken;
-	size_type begIdx, endIdx;
-
-	begIdx = input.find_first_not_of (delims);
-	while (begIdx != std::basic_string<T>::npos)
-	{
-		endIdx = input.find_first_of (delims, begIdx);
-		if (endIdx == std::basic_string<T>::npos)
-		{
-			endIdx = input.length();
-		}
-
-		currToken = input.substr(begIdx, endIdx - begIdx);
-		trim (currToken);
-		tokens.push_back(currToken);
-		begIdx = input.find_first_not_of (delims, endIdx);
-	}
-}
-
-extern LLFastTimer::DeclareTimer STRING_LOCALIZATION;
-
-// static
-template<class T> 
-S32 LLStringUtilBase<T>::format(std::basic_string<T>& s, const format_map_t& substitutions)
-{
-	LLFastTimer ft(STRING_LOCALIZATION);
-	S32 res = 0;
-
-	std::basic_ostringstream<T> output;
-	// match strings like [NAME,number,3]
-	const boost::regex key("\\[((\\s)*([0-9_A-Za-z]+)((\\s)*,(\\s)*[0-9_A-Za-z\\s]*){0,2}(\\s)*)]");
-
-
-	typename std::basic_string<T>::const_iterator start = s.begin();
-	typename std::basic_string<T>::const_iterator end = s.end();
-	boost::smatch match;
-	
-
-	while (boost::regex_search(start, end, match, key, boost::match_default))
-	{
-		bool found_replacement = false;
-		std::vector<std::basic_string<T> > tokens;
-		std::basic_string<T> replacement;
-
-		getTokens (std::basic_string<T>(match[1].first, match[1].second), tokens);
-
-		if (tokens.size() == 1)
-		{
-			found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
-		}
-		else if (tokens[1] == "number")
-		{
-			std::basic_string<T> param = "0";
-
-			if (tokens.size() > 2) param = tokens[2];
-			found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
-			if (found_replacement) formatNumber (replacement, param);
-		}
-		else if (tokens[1] == "datetime")
-		{
-			std::basic_string<T> param;
-			if (tokens.size() > 2) param = tokens[2];
-			
-			format_map_t::const_iterator iter = substitutions.find("datetime");
-			if (iter != substitutions.end())
-			{
-				S32 secFromEpoch = 0;
-				BOOL r = LLStringUtil::convertToS32(iter->second, secFromEpoch);
-				if (r)
-				{
-					found_replacement = formatDatetime(replacement, tokens[0], param, secFromEpoch);
-				}
-			}
-		}
-
-		if (found_replacement)
-		{
-			output << std::basic_string<T>(start, match[0].first) << replacement;
-			res++;
-		}
-		else
-		{
-			// we had no replacement, so leave the string we searched for so that it gets noticed by QA
-			// "hello [NAME_NOT_FOUND]" is output
-			output << std::basic_string<T>(start, match[0].second);
-		}
-		
-		// update search position 
-		start = match[0].second; 
-	}
-	// send the remainder of the string (with no further matches for bracketed names)
-	output << std::basic_string<T>(start, end);
-	s = output.str();
-	return res;
-}
-
-//static
-template<class T>
-S32 LLStringUtilBase<T>::format(std::basic_string<T>& s, const LLSD& substitutions)
-{
-	LLFastTimer ft(STRING_LOCALIZATION);
-
-	S32 res = 0;
-
-	if (!substitutions.isMap()) 
-	{
-		return res;
-	}
-
-	std::basic_ostringstream<T> output;
-	// match strings like [NAME,number,3]
-	const boost::regex key("\\[((\\s)*([0-9_A-Za-z]+)((\\s)*,(\\s)*[0-9_A-Za-z\\s]*){0,2}(\\s)*)]");
-
-
-	typename std::basic_string<T>::const_iterator start = s.begin();
-	typename std::basic_string<T>::const_iterator end = s.end();
-	boost::smatch match;
-	
-
-	while (boost::regex_search(start, end, match, key, boost::match_default))
-	{
-		bool found_replacement = false;
-		std::vector<std::basic_string<T> > tokens;
-		std::basic_string<T> replacement;
-
-		getTokens (std::basic_string<T>(match[1].first, match[1].second), tokens);
-
-		if (tokens.size() == 1)
-		{
-			found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
-		}
-		else if (tokens[1] == "number")
-		{
-			std::basic_string<T> param = "0";
-
-			if (tokens.size() > 2) param = tokens[2];
-			found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
-			if (found_replacement) formatNumber (replacement, param);
-		}
-		else if (tokens[1] == "datetime")
-		{
-			std::basic_string<T> param;
-			if (tokens.size() > 2) param = tokens[2];
-			
-			S32 secFromEpoch = (S32) substitutions["datetime"].asInteger();
-			found_replacement = formatDatetime (replacement, tokens[0], param, secFromEpoch);
-		}
-
-		if (found_replacement)
-		{
-			output << std::basic_string<T>(start, match[0].first) << replacement;
-			res++;
-		}
-		else
-		{
-			// we had no replacement, so leave the string we searched for so that it gets noticed by QA
-			// "hello [NAME_NOT_FOUND]" is output
-			output << std::basic_string<T>(start, match[0].second);
-		}
-		
-		// update search position 
-		start = match[0].second; 
-	}
-	// send the remainder of the string (with no further matches for bracketed names)
-	output << std::basic_string<T>(start, end);
-	s = output.str();
-	return res;
-}
-
-// static
-template<class T>
-bool LLStringUtilBase<T>::simpleReplacement(std::basic_string<T> &replacement, std::basic_string<T> token, const format_map_t& substitutions)
-{
-	// see if we have a replacement for the bracketed string (without the brackets)
-	// test first using has() because if we just look up with operator[] we get back an
-	// empty string even if the value is missing. We want to distinguish between 
-	// missing replacements and deliberately empty replacement strings.
-	format_map_t::const_iterator iter = substitutions.find(token);
-	if (iter != substitutions.end())
-	{
-		replacement = iter->second;
-		return true;
-	}
-	// if not, see if there's one WITH brackets
-	iter = substitutions.find(std::basic_string<T>("[" + token + "]"));
-	if (iter != substitutions.end())
-	{
-		replacement = iter->second;
-		return true;
-	}
-
-	return false;
-}
-
-// static
-template<class T>
-bool LLStringUtilBase<T>::simpleReplacement(std::basic_string<T> &replacement, std::basic_string<T> token, const LLSD& substitutions)
-{
-	// see if we have a replacement for the bracketed string (without the brackets)
-	// test first using has() because if we just look up with operator[] we get back an
-	// empty string even if the value is missing. We want to distinguish between 
-	// missing replacements and deliberately empty replacement strings.
-	if (substitutions.has(token))
-	{
-		replacement = substitutions[token].asString();
-		return true;
-	}
-	// if not, see if there's one WITH brackets
-	else if (substitutions.has(std::basic_string<T>("[" + token + "]")))
-	{
-		replacement = substitutions[std::basic_string<T>("[" + token + "]")].asString();
-		return true;
-	}
-
-	return false;
-}
-
-// static
-template<class T>
-void LLStringUtilBase<T>::formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals)
-{
-	typedef typename std::basic_string<T>::size_type string_size_type_t;
-	std::basic_stringstream<T> strStream;
-	S32 intDecimals = 0;
-
-	convertToS32 (decimals, intDecimals);
-	if (!sLocale.empty())
-	{
-		strStream.imbue (std::locale(sLocale.c_str()));
-	}
-
-	if (!intDecimals)
-	{
-		S32 intStr;
-
-		if (convertToS32(numStr, intStr))
-		{
-			strStream << intStr;
-			numStr = strStream.str();
-		}
-	}
-	else
-	{
-		F32 floatStr;
-
-		if (convertToF32(numStr, floatStr))
-		{
-			strStream << std::fixed << std::showpoint << std::setprecision(intDecimals) << floatStr;
-			numStr = strStream.str();
-		}
-	}
-}
-
-// static
-template<class T>
-bool LLStringUtilBase<T>::formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token,
-										 std::basic_string<T> param, S32 secFromEpoch)
-{
-	if (param == "local")   // local
-	{
-		secFromEpoch -= LLStringOps::getLocalTimeOffset();
-	}
-	else if (param != "utc") // slt
-	{
-		secFromEpoch -= LLStringOps::getSltOffset();
-	}
-		
-	// if never fell into those two ifs above, param must be utc
-	if (secFromEpoch < 0) secFromEpoch = 0;
-
-	LLDate * datetime = new LLDate((F64)secFromEpoch);
-	std::string code = LLStringOps::getDatetimeCode (token);
-
-	// special case to handle timezone
-	if (code == "%Z") {
-		if (param == "utc") replacement = "GMT";
-		else if (param != "local") replacement = LLStringOps::getDaylightSavings()? "PDT" : "PST";
-		return true;
-	}
+////////////////////////////////////////////////////////////
 
-	replacement = datetime->toHTTPDateString(code);
-	if (code.empty())
-	{
-		return false;
-	}
-	else
-	{
-		return true;
-	}
-}
 
 // static
 template<class T> 
-- 
cgit v1.2.3