/**
       Recursively translate all environment variables with their actual values.

       \param[in] input String to remove environment variables from.
       \returns String where all environment variables have been translated.
       \throws SCXRunAsConfigurationException if a loop in environmen variables is suspected.
    */
    const std::wstring RunAsConfigurator::ResolveEnvVars(const std::wstring& input) const
    {
        static const std::wstring allowedVarNameChars(L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_");
        
        // We need to know when we run into an infinite loop.
        int numberOfVariableSubstitutionsAllowed = 100;
        std::wstring output(input);
        for (std::wstring::size_type varstart = output.find(L'$');
             varstart != std::wstring::npos;
             varstart = output.find(L'$', varstart))
        {
            std::wstring variableName;
            std::wstring::size_type varend;
            if (L'{' == output[varstart + 1])
            {
                varend = output.find(L'}', varstart + 2);
                if (varend == std::wstring::npos)
                {
                    throw SCXRunAsConfigurationException(
                        std::wstring(L"Configuration value ")
                        .append(input)
                        .append(L" seems to be malformed. '{' and '}' are not matching."), SCXSRCLOCATION);
                }
                variableName = output.substr(varstart + 2, varend - 2 - varstart);
            }
            else
            {
                varend = output.find_first_not_of(allowedVarNameChars, varstart + 1);
                if (varend == std::wstring::npos)
                {
                    varend = output.size();
                }
                --varend; // Index of the last character in the variable name.

                variableName = output.substr(varstart + 1, varend - varstart);
            }

            const char *variableValuePtr = ::getenv(StrToMultibyte(variableName).c_str());
            if (0 == variableValuePtr)
            {
                output.erase(varstart, varend - varstart + 1);
            }
            else
            {
                output.replace(varstart, varend - varstart + 1, StrFromMultibyte(variableValuePtr));
            }

            --numberOfVariableSubstitutionsAllowed;
            if (0 == numberOfVariableSubstitutionsAllowed)
            {
                throw SCXRunAsConfigurationException(
                    std::wstring(L"Configuration value ")
                    .append(input)
                    .append(L" seems to contain environment variables that form an infinite recursion loop."), SCXSRCLOCATION);
            }
        }
        return output;
    }
    /**
    Translate install date from string to SCXCalendarTime

    Parameters:  installDate - its format like Aug 04 2010 10:24

    */
    void InstalledSoftwareInstance::SetInstallDate(const wstring& installDate)
    {
        tm          installtm;
        const std::string nsInstallDate = StrToMultibyte(installDate);
        const char *buf      = nsInstallDate.c_str();
        size_t      ccLength = installDate.length();
        const char *bufend   = buf + ccLength;
        const char *format   = "%b %d %Y %H:%M";
        const char *ret      = strptime(buf, format, &installtm);

        if (ret == bufend)
        {
            SCXCoreLib::SCXCalendarTime instDate((scxyear)(installtm.tm_year + 1900), (scxmonth)(installtm.tm_mon + 1), (scxday)(installtm.tm_mday));
            instDate.SetHour((scxhour)(installtm.tm_hour));
            instDate.SetMinute((scxminute)(installtm.tm_min));
            m_installDate = instDate;
        }
        else
        {
            SCX_LOGWARNING(m_log, StrAppend(L"strptime installDate fails: ", installDate));
            m_installDate = SCXCalendarTime::FromPosixTime(0);
        }
    }