Skip to content
Snippets Groups Projects
llstring.cpp 31.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		{
    			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::getPacificTimeOffset();
    
    	}
    		
    	// if never fell into those two ifs above, param must be utc
    	if (secFromEpoch < 0) secFromEpoch = 0;
    
    
    	LLDate datetime((F64)secFromEpoch);
    
    	std::string code = LLStringOps::getDatetimeCode (token);
    
    	// special case to handle timezone
    	if (code == "%Z") {
    
    Steven Bennetts's avatar
    Steven Bennetts committed
    		if (param == "utc")
    
    Steven Bennetts's avatar
    Steven Bennetts committed
    			replacement = "GMT";
    
    		}
    		else if (param == "local")
    		{
    			replacement = "";		// user knows their own timezone
    		}
    		else
    		{
    			// "slt" = Second Life Time, which is deprecated.
    			// If not utc or user local time, fallback to Pacific time
    
    			replacement = LLStringOps::getPacificDaylightTime() ? "PDT" : "PST";
    
    
    	//EXT-7013
    	//few codes are not suppotred by strtime function (example - weekdays for Japanise)
    	//so use predefined ones
    	
    	//if sWeekDayList is not empty than current locale doesn't support
            //weekday name.
    	time_t loc_seconds = (time_t) secFromEpoch;
    	if(LLStringOps::sWeekDayList.size() == 7 && code == "%A")
    	{
    		struct tm * gmt = gmtime (&loc_seconds);
    		replacement = LLStringOps::sWeekDayList[gmt->tm_wday];
    	}
    	else if(LLStringOps::sWeekDayShortList.size() == 7 && code == "%a")
    	{
    		struct tm * gmt = gmtime (&loc_seconds);
    		replacement = LLStringOps::sWeekDayShortList[gmt->tm_wday];
    	}
    	else if(LLStringOps::sMonthList.size() == 12 && code == "%B")
    	{
    		struct tm * gmt = gmtime (&loc_seconds);
    		replacement = LLStringOps::sWeekDayList[gmt->tm_mon];
    	}
    	else if( !LLStringOps::sDayFormat.empty() && code == "%d" )
    	{
    		struct tm * gmt = gmtime (&loc_seconds);
    		LLStringUtil::format_map_t args;
    		args["[MDAY]"] = llformat ("%d", gmt->tm_mday);
    		replacement = LLStringOps::sDayFormat;
    		LLStringUtil::format(replacement, args);
    	}
    	else if( !LLStringOps::sAM.empty() && !LLStringOps::sPM.empty() && code == "%p" )
    	{
    		struct tm * gmt = gmtime (&loc_seconds);
    		if(gmt->tm_hour<12)
    		{
    			replacement = LLStringOps::sAM;
    		}
    		else
    		{
    			replacement = LLStringOps::sPM;
    		}
    	}
    	else
    	{
    		replacement = datetime.toHTTPDateString(code);
    	}
    
    
    	// *HACK: delete leading zero from hour string in case 'hour12' (code = %I) time format
    	// to show time without leading zero, e.g. 08:16 -> 8:16 (EXT-2738).
    	// We could have used '%l' format instead, but it's not supported by Windows.
    	if(code == "%I" && token == "hour12" && replacement.at(0) == '0')
    	{
    		replacement = replacement.at(1);
    	}
    
    
    // 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() == 0)
    		{
    			found_replacement = false;
    		}
    		else 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, use the string as is
    			// e.g. "hello [MISSING_REPLACEMENT]" or "-=[Stylized Name]=-"
    			output += std::string(s, key_start, start-key_start);
    
    		}
    		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() == 0)
    		{
    			found_replacement = false;
    		}
    		else 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, use the string as is
    			// e.g. "hello [MISSING_REPLACEMENT]" or "-=[Stylized Name]=-"
    			output += std::string(s, key_start, start-key_start);
    
    		}
    		tokens.clear();
    	}
    	// send the remainder of the string (with no further matches for bracketed names)
    	output += std::string(s, start);
    	s = output;
    	return res;
    }
    
    
    James Cook's avatar
    James Cook committed
    ////////////////////////////////////////////////////////////
    // Testing
    
    #ifdef _DEBUG
    
    template<class T> 
    
    void LLStringUtilBase<T>::testHarness()
    
    James Cook's avatar
    James Cook committed
    {
    
    James Cook's avatar
    James Cook committed
    	
    	llassert( s1.c_str() == NULL );
    	llassert( s1.size() == 0 );
    	llassert( s1.empty() );
    	
    
    James Cook's avatar
    James Cook committed
    	llassert( !strcmp( s2.c_str(), "hello" ) );
    	llassert( s2.size() == 5 ); 
    	llassert( !s2.empty() );
    
    James Cook's avatar
    James Cook committed
    
    	llassert( "hello" == s2 );
    	llassert( s2 == "hello" );
    	llassert( s2 > "gello" );
    	llassert( "gello" < s2 );
    	llassert( "gello" != s2 );
    	llassert( s2 != "gello" );
    
    
    James Cook's avatar
    James Cook committed
    	llassert( !s4.empty() );
    	s4.empty();
    	llassert( s4.empty() );
    	
    
    James Cook's avatar
    James Cook committed
    	llassert( s5.empty() );
    	
    	llassert( isValidIndex(s5, 0) );
    	llassert( !isValidIndex(s5, 1) );
    	
    	s3 = s2;
    	s4 = "hello again";
    	
    	s4 += "!";
    	s4 += s4;
    	llassert( s4 == "hello again!hello again!" );
    	
    	
    
    	std::string s6 = s2 + " " + s2;
    	std::string s7 = s6;
    
    James Cook's avatar
    James Cook committed
    	llassert( s6 == s7 );
    	llassert( !( s6 != s7) );
    	llassert( !(s6 < s7) );
    	llassert( !(s6 > s7) );
    	
    	llassert( !(s6 == "hi"));
    	llassert( s6 == "hello hello");
    	llassert( s6 < "hi");
    	
    	llassert( s6[1] == 'e' );
    	s6[1] = 'f';
    	llassert( s6[1] == 'f' );
    	
    	s2.erase( 4, 1 );
    	llassert( s2 == "hell");
    	s2.insert( 0, 'y' );
    	llassert( s2 == "yhell");
    	s2.erase( 1, 3 );
    	llassert( s2 == "yl");
    	s2.insert( 1, "awn, don't yel");
    	llassert( s2 == "yawn, don't yell");
    	
    
    	std::string s8 = s2.substr( 6, 5 );
    
    James Cook's avatar
    James Cook committed
    	llassert( s8 == "don't"  );
    	
    
    	std::string s9 = "   \t\ntest  \t\t\n  ";
    
    James Cook's avatar
    James Cook committed
    	trim(s9);
    	llassert( s9 == "test"  );
    
    	s8 = "abc123&*(ABC";
    
    	s9 = s8;
    	toUpper(s9);
    	llassert( s9 == "ABC123&*(ABC"  );
    
    	s9 = s8;
    	toLower(s9);
    	llassert( s9 == "abc123&*(abc"  );
    
    
    
    	std::string s10( 10, 'x' );
    
    James Cook's avatar
    James Cook committed
    	llassert( s10 == "xxxxxxxxxx" );
    
    
    	std::string s11( "monkey in the middle", 7, 2 );
    
    James Cook's avatar
    James Cook committed
    	llassert( s11 == "in" );
    
    
    James Cook's avatar
    James Cook committed
    	s12 += "foo";
    	llassert( s12 == "foo" );
    
    
    James Cook's avatar
    James Cook committed
    	s13 += 'f';
    	llassert( s13 == "f" );
    }
    
    
    #endif  // _DEBUG