110448Snilay@cs.wisc.edu/* Copyright (c) 2012 Massachusetts Institute of Technology
210448Snilay@cs.wisc.edu *
310448Snilay@cs.wisc.edu * Permission is hereby granted, free of charge, to any person obtaining a copy
410448Snilay@cs.wisc.edu * of this software and associated documentation files (the "Software"), to deal
510448Snilay@cs.wisc.edu * in the Software without restriction, including without limitation the rights
610448Snilay@cs.wisc.edu * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
710448Snilay@cs.wisc.edu * copies of the Software, and to permit persons to whom the Software is
810448Snilay@cs.wisc.edu * furnished to do so, subject to the following conditions:
910448Snilay@cs.wisc.edu *
1010448Snilay@cs.wisc.edu * The above copyright notice and this permission notice shall be included in
1110448Snilay@cs.wisc.edu * all copies or substantial portions of the Software.
1210448Snilay@cs.wisc.edu *
1310448Snilay@cs.wisc.edu * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1410448Snilay@cs.wisc.edu * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1510448Snilay@cs.wisc.edu * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1610448Snilay@cs.wisc.edu * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1710448Snilay@cs.wisc.edu * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1810448Snilay@cs.wisc.edu * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1910448Snilay@cs.wisc.edu * THE SOFTWARE.
2010448Snilay@cs.wisc.edu */
2110448Snilay@cs.wisc.edu
2210447Snilay@cs.wisc.edu#include "String.h"
2310447Snilay@cs.wisc.edu
2410447Snilay@cs.wisc.edu#include <cstdarg>
2510447Snilay@cs.wisc.edu#include <cstdio>
2610447Snilay@cs.wisc.edu#include <iostream>
2710447Snilay@cs.wisc.edu#include <ios>
2810447Snilay@cs.wisc.edu
2910447Snilay@cs.wisc.edunamespace LibUtil
3010447Snilay@cs.wisc.edu{
3110447Snilay@cs.wisc.edu    const unsigned int String::msBufferSize = 4096;
3210447Snilay@cs.wisc.edu
3310447Snilay@cs.wisc.edu    String String::format(const String& format_, ...)
3410447Snilay@cs.wisc.edu    {
3510447Snilay@cs.wisc.edu        char buffer[msBufferSize];
3610447Snilay@cs.wisc.edu
3710447Snilay@cs.wisc.edu        va_list args;
3810447Snilay@cs.wisc.edu        va_start(args, format_);
3910447Snilay@cs.wisc.edu        vsnprintf(buffer, msBufferSize, format_.c_str(), args);
4010447Snilay@cs.wisc.edu        va_end(args);
4110447Snilay@cs.wisc.edu
4210447Snilay@cs.wisc.edu        return (String)(buffer);
4310447Snilay@cs.wisc.edu    }
4410447Snilay@cs.wisc.edu
4510447Snilay@cs.wisc.edu    String String::format(const String& format_, va_list args_)
4610447Snilay@cs.wisc.edu    {
4710447Snilay@cs.wisc.edu        char buffer[msBufferSize];
4810447Snilay@cs.wisc.edu
4910447Snilay@cs.wisc.edu        vsnprintf(buffer, msBufferSize, format_.c_str(), args_);
5010447Snilay@cs.wisc.edu
5110447Snilay@cs.wisc.edu        return (String)(buffer);
5210447Snilay@cs.wisc.edu    }
5310447Snilay@cs.wisc.edu
5410447Snilay@cs.wisc.edu    String::String()
5510447Snilay@cs.wisc.edu    {}
5610447Snilay@cs.wisc.edu
5710447Snilay@cs.wisc.edu    String::String(const string& str_)
5810447Snilay@cs.wisc.edu        : string(str_)
5910447Snilay@cs.wisc.edu    {}
6010447Snilay@cs.wisc.edu
6110447Snilay@cs.wisc.edu    String::String(const char* str_, size_t n_)
6210447Snilay@cs.wisc.edu        : string(str_, n_)
6310447Snilay@cs.wisc.edu    {}
6410447Snilay@cs.wisc.edu
6510447Snilay@cs.wisc.edu    String::String(const char* str_)
6610447Snilay@cs.wisc.edu        : string(str_)
6710447Snilay@cs.wisc.edu    {}
6810447Snilay@cs.wisc.edu
6910447Snilay@cs.wisc.edu    String::String(size_t n_, char c_)
7010447Snilay@cs.wisc.edu        : string(n_, c_)
7110447Snilay@cs.wisc.edu    {}
7210447Snilay@cs.wisc.edu
7310447Snilay@cs.wisc.edu    String::String(int value_)
7410447Snilay@cs.wisc.edu        : string(toString<int>(value_))
7510447Snilay@cs.wisc.edu    {}
7610447Snilay@cs.wisc.edu
7710447Snilay@cs.wisc.edu    String::String(unsigned int value_)
7810447Snilay@cs.wisc.edu        : string(toString<unsigned int>(value_))
7910447Snilay@cs.wisc.edu    {}
8010447Snilay@cs.wisc.edu
8110447Snilay@cs.wisc.edu    String::String(long value_)
8210447Snilay@cs.wisc.edu        : string(toString<long>(value_))
8310447Snilay@cs.wisc.edu    {}
8410447Snilay@cs.wisc.edu
8510447Snilay@cs.wisc.edu    String::String(unsigned long value_)
8610447Snilay@cs.wisc.edu        : string(toString<unsigned long>(value_))
8710447Snilay@cs.wisc.edu    {}
8810447Snilay@cs.wisc.edu
8910447Snilay@cs.wisc.edu    String::String(float value_)
9010447Snilay@cs.wisc.edu        : string(toString<float>(value_))
9110447Snilay@cs.wisc.edu    {}
9210447Snilay@cs.wisc.edu
9310447Snilay@cs.wisc.edu    String::String(double value_)
9410447Snilay@cs.wisc.edu        : string(toString<double>(value_))
9510447Snilay@cs.wisc.edu    {}
9610447Snilay@cs.wisc.edu
9710447Snilay@cs.wisc.edu    String::String(bool value_)
9810447Snilay@cs.wisc.edu        : string(toString<bool>(value_))
9910447Snilay@cs.wisc.edu    {}
10010447Snilay@cs.wisc.edu
10110447Snilay@cs.wisc.edu    String::~String()
10210447Snilay@cs.wisc.edu    {}
10310447Snilay@cs.wisc.edu
10410447Snilay@cs.wisc.edu    String& String::trim()
10510447Snilay@cs.wisc.edu    {
10610447Snilay@cs.wisc.edu        // Remove leading and trailing whitespace
10710447Snilay@cs.wisc.edu        static const char whitespace[] = " \n\t\v\r\f";
10810447Snilay@cs.wisc.edu        erase(0, find_first_not_of(whitespace));
10910447Snilay@cs.wisc.edu        erase(find_last_not_of(whitespace) + 1U);
11010447Snilay@cs.wisc.edu        return (*this);
11110447Snilay@cs.wisc.edu    }
11210447Snilay@cs.wisc.edu
11310447Snilay@cs.wisc.edu    String& String::substitute(const String& str1_, const String& str2_)
11410447Snilay@cs.wisc.edu    {
11510447Snilay@cs.wisc.edu        size_t str1Size = str1_.size();
11610447Snilay@cs.wisc.edu        size_t str2Size = str2_.size();
11710447Snilay@cs.wisc.edu
11810447Snilay@cs.wisc.edu        size_t pos;
11910447Snilay@cs.wisc.edu        pos = find(str1_);
12010447Snilay@cs.wisc.edu        while(pos != string::npos)
12110447Snilay@cs.wisc.edu        {
12210447Snilay@cs.wisc.edu            replace(pos, str1Size, str2_);
12310447Snilay@cs.wisc.edu            pos += str2Size;
12410447Snilay@cs.wisc.edu            pos = find(str1_, pos);
12510447Snilay@cs.wisc.edu        }
12610447Snilay@cs.wisc.edu        return (*this);
12710447Snilay@cs.wisc.edu    }
12810447Snilay@cs.wisc.edu
12910447Snilay@cs.wisc.edu    vector<String> String::split(const char* delimiters_) const
13010447Snilay@cs.wisc.edu    {
13110447Snilay@cs.wisc.edu        vector<String> result;
13210447Snilay@cs.wisc.edu
13310447Snilay@cs.wisc.edu        if(size() == 0)
13410447Snilay@cs.wisc.edu        {
13510447Snilay@cs.wisc.edu            return result;
13610447Snilay@cs.wisc.edu        }
13710447Snilay@cs.wisc.edu
13810447Snilay@cs.wisc.edu        size_t currPos, nextPos;
13910447Snilay@cs.wisc.edu        currPos = 0;
14010447Snilay@cs.wisc.edu        nextPos = find_first_of(delimiters_);
14110447Snilay@cs.wisc.edu        while(1)
14210447Snilay@cs.wisc.edu        {
14310447Snilay@cs.wisc.edu            if(nextPos == string::npos)
14410447Snilay@cs.wisc.edu            {
14510447Snilay@cs.wisc.edu                if(currPos != size())
14610447Snilay@cs.wisc.edu                {
14710447Snilay@cs.wisc.edu                    result.push_back(substr(currPos));
14810447Snilay@cs.wisc.edu                }
14910447Snilay@cs.wisc.edu                break;
15010447Snilay@cs.wisc.edu            }
15110447Snilay@cs.wisc.edu
15210447Snilay@cs.wisc.edu            if(nextPos != currPos)
15310447Snilay@cs.wisc.edu            {
15410447Snilay@cs.wisc.edu                result.push_back(substr(currPos, nextPos - currPos));
15510447Snilay@cs.wisc.edu            }
15610447Snilay@cs.wisc.edu            currPos = nextPos + 1;
15710447Snilay@cs.wisc.edu            nextPos = find_first_of(delimiters_, currPos);
15810447Snilay@cs.wisc.edu        }
15910447Snilay@cs.wisc.edu
16010447Snilay@cs.wisc.edu        return result;
16110447Snilay@cs.wisc.edu    }
16210447Snilay@cs.wisc.edu
16310447Snilay@cs.wisc.edu    vector<String> String::split(const String* delimiters_, unsigned int num_delimiters_) const
16410447Snilay@cs.wisc.edu    {
16510447Snilay@cs.wisc.edu        vector<String> result;
16610447Snilay@cs.wisc.edu
16710447Snilay@cs.wisc.edu        if(size() == 0)
16810447Snilay@cs.wisc.edu        {
16910447Snilay@cs.wisc.edu            return result;
17010447Snilay@cs.wisc.edu        }
17110447Snilay@cs.wisc.edu
17210447Snilay@cs.wisc.edu        if(num_delimiters_ == 1)
17310447Snilay@cs.wisc.edu        {
17410447Snilay@cs.wisc.edu            size_t currPos, nextPos;
17510447Snilay@cs.wisc.edu            currPos = 0;
17610447Snilay@cs.wisc.edu            nextPos = find(delimiters_[0]);
17710447Snilay@cs.wisc.edu            while(1)
17810447Snilay@cs.wisc.edu            {
17910447Snilay@cs.wisc.edu                if(nextPos == String::npos)
18010447Snilay@cs.wisc.edu                {
18110447Snilay@cs.wisc.edu                    result.push_back(substr(currPos));
18210447Snilay@cs.wisc.edu                    break;
18310447Snilay@cs.wisc.edu                }
18410447Snilay@cs.wisc.edu
18510447Snilay@cs.wisc.edu                if(nextPos != currPos)
18610447Snilay@cs.wisc.edu                {
18710447Snilay@cs.wisc.edu                    result.push_back(substr(currPos, nextPos - currPos));
18810447Snilay@cs.wisc.edu                }
18910447Snilay@cs.wisc.edu                currPos = nextPos + delimiters_[0].size();
19010447Snilay@cs.wisc.edu                nextPos = find(delimiters_[0], currPos);
19110447Snilay@cs.wisc.edu            }
19210447Snilay@cs.wisc.edu        }
19310447Snilay@cs.wisc.edu        else
19410447Snilay@cs.wisc.edu        {
19510447Snilay@cs.wisc.edu            // Currently the length of the delimiters are not checked
19610447Snilay@cs.wisc.edu            unsigned int delimiterLength = 0;
19710447Snilay@cs.wisc.edu            size_t currPos, nextPos;
19810447Snilay@cs.wisc.edu            currPos = 0;
19910447Snilay@cs.wisc.edu            nextPos = size();
20010447Snilay@cs.wisc.edu            for(unsigned int i = 0; i < num_delimiters_; ++i)
20110447Snilay@cs.wisc.edu            {
20210447Snilay@cs.wisc.edu                size_t tempPos = find(delimiters_[i], currPos);
20310447Snilay@cs.wisc.edu                if((tempPos != String::npos) && (tempPos < nextPos))
20410447Snilay@cs.wisc.edu                {
20510447Snilay@cs.wisc.edu                    nextPos = tempPos;
20610447Snilay@cs.wisc.edu                    delimiterLength = delimiters_[i].size();
20710447Snilay@cs.wisc.edu                }
20810447Snilay@cs.wisc.edu            }
20910447Snilay@cs.wisc.edu            while(1)
21010447Snilay@cs.wisc.edu            {
21110447Snilay@cs.wisc.edu                if((nextPos == String::npos) || (nextPos == size()))
21210447Snilay@cs.wisc.edu                {
21310447Snilay@cs.wisc.edu                    result.push_back(substr(currPos));
21410447Snilay@cs.wisc.edu                    break;
21510447Snilay@cs.wisc.edu                }
21610447Snilay@cs.wisc.edu
21710447Snilay@cs.wisc.edu                if(nextPos != currPos)
21810447Snilay@cs.wisc.edu                {
21910447Snilay@cs.wisc.edu                    result.push_back(substr(currPos, nextPos - currPos));
22010447Snilay@cs.wisc.edu                }
22110447Snilay@cs.wisc.edu                currPos = nextPos + delimiterLength;
22210447Snilay@cs.wisc.edu                nextPos = size();
22310447Snilay@cs.wisc.edu                delimiterLength = 0;
22410447Snilay@cs.wisc.edu                for(unsigned int i = 0; i < num_delimiters_; ++i)
22510447Snilay@cs.wisc.edu                {
22610447Snilay@cs.wisc.edu                    size_t tempPos = find(delimiters_[i], currPos);
22710447Snilay@cs.wisc.edu                    if((tempPos != String::npos) && (tempPos < nextPos))
22810447Snilay@cs.wisc.edu                    {
22910447Snilay@cs.wisc.edu                        nextPos = tempPos;
23010447Snilay@cs.wisc.edu                        delimiterLength = delimiters_[i].size();
23110447Snilay@cs.wisc.edu                    }
23210447Snilay@cs.wisc.edu                }
23310447Snilay@cs.wisc.edu            }
23410447Snilay@cs.wisc.edu        }
23510447Snilay@cs.wisc.edu        return result;
23610447Snilay@cs.wisc.edu    }
23710447Snilay@cs.wisc.edu
23810447Snilay@cs.wisc.edu    vector<String> String::splitByString(const String& delimiter_) const
23910447Snilay@cs.wisc.edu    {
24010447Snilay@cs.wisc.edu        return split(&delimiter_, 1);
24110447Snilay@cs.wisc.edu    }
24210447Snilay@cs.wisc.edu
24310447Snilay@cs.wisc.edu    bool String::contain(const String& str_) const
24410447Snilay@cs.wisc.edu    {
24510447Snilay@cs.wisc.edu        return (find(str_) != String::npos);
24610447Snilay@cs.wisc.edu    }
24710447Snilay@cs.wisc.edu
24810447Snilay@cs.wisc.edu    const char* String::toCString() const
24910447Snilay@cs.wisc.edu    {
25010447Snilay@cs.wisc.edu        return this->c_str();
25110447Snilay@cs.wisc.edu    }
25210447Snilay@cs.wisc.edu
25310447Snilay@cs.wisc.edu    int String::toInt() const
25410447Snilay@cs.wisc.edu    {
25510447Snilay@cs.wisc.edu        return fromString<int>(*this);
25610447Snilay@cs.wisc.edu    }
25710447Snilay@cs.wisc.edu
25810447Snilay@cs.wisc.edu    unsigned int String::toUInt() const
25910447Snilay@cs.wisc.edu    {
26010447Snilay@cs.wisc.edu        return fromString<unsigned int>(*this);
26110447Snilay@cs.wisc.edu    }
26210447Snilay@cs.wisc.edu
26310447Snilay@cs.wisc.edu    long String::toLong() const
26410447Snilay@cs.wisc.edu    {
26510447Snilay@cs.wisc.edu        return fromString<long>(*this);
26610447Snilay@cs.wisc.edu    }
26710447Snilay@cs.wisc.edu
26810447Snilay@cs.wisc.edu    unsigned long String::toULong() const
26910447Snilay@cs.wisc.edu    {
27010447Snilay@cs.wisc.edu        return fromString<unsigned long>(*this);
27110447Snilay@cs.wisc.edu    }
27210447Snilay@cs.wisc.edu
27310447Snilay@cs.wisc.edu    float String::toFloat() const
27410447Snilay@cs.wisc.edu    {
27510447Snilay@cs.wisc.edu        return fromString<float>(*this);
27610447Snilay@cs.wisc.edu    }
27710447Snilay@cs.wisc.edu
27810447Snilay@cs.wisc.edu    double String::toDouble() const
27910447Snilay@cs.wisc.edu    {
28010447Snilay@cs.wisc.edu        return fromString<double>(*this);
28110447Snilay@cs.wisc.edu    }
28210447Snilay@cs.wisc.edu
28310447Snilay@cs.wisc.edu    bool String::toBool() const
28410447Snilay@cs.wisc.edu    {
28510447Snilay@cs.wisc.edu        return fromString<bool>(*this);
28610447Snilay@cs.wisc.edu    }
28710447Snilay@cs.wisc.edu
28810447Snilay@cs.wisc.edu    String::operator const char*() const
28910447Snilay@cs.wisc.edu    {
29010447Snilay@cs.wisc.edu        return this->c_str();
29110447Snilay@cs.wisc.edu    }
29210447Snilay@cs.wisc.edu
29310447Snilay@cs.wisc.edu    String::operator int() const
29410447Snilay@cs.wisc.edu    {
29510447Snilay@cs.wisc.edu        return fromString<int>(*this);
29610447Snilay@cs.wisc.edu    }
29710447Snilay@cs.wisc.edu
29810447Snilay@cs.wisc.edu    String::operator unsigned int() const
29910447Snilay@cs.wisc.edu    {
30010447Snilay@cs.wisc.edu        return fromString<unsigned int>(*this);
30110447Snilay@cs.wisc.edu    }
30210447Snilay@cs.wisc.edu
30310447Snilay@cs.wisc.edu    String::operator long() const
30410447Snilay@cs.wisc.edu    {
30510447Snilay@cs.wisc.edu        return fromString<long>(*this);
30610447Snilay@cs.wisc.edu    }
30710447Snilay@cs.wisc.edu
30810447Snilay@cs.wisc.edu    String::operator unsigned long() const
30910447Snilay@cs.wisc.edu    {
31010447Snilay@cs.wisc.edu        return fromString<unsigned long>(*this);
31110447Snilay@cs.wisc.edu    }
31210447Snilay@cs.wisc.edu
31310447Snilay@cs.wisc.edu    String::operator float() const
31410447Snilay@cs.wisc.edu    {
31510447Snilay@cs.wisc.edu        return fromString<float>(*this);
31610447Snilay@cs.wisc.edu    }
31710447Snilay@cs.wisc.edu
31810447Snilay@cs.wisc.edu    String::operator double() const
31910447Snilay@cs.wisc.edu    {
32010447Snilay@cs.wisc.edu        return fromString<double>(*this);
32110447Snilay@cs.wisc.edu    }
32210447Snilay@cs.wisc.edu
32310447Snilay@cs.wisc.edu    String::operator bool() const
32410447Snilay@cs.wisc.edu    {
32510447Snilay@cs.wisc.edu        return fromString<bool>(*this);
32610447Snilay@cs.wisc.edu    }
32710447Snilay@cs.wisc.edu
32810447Snilay@cs.wisc.edu    String& String::operator=(char c_)
32910447Snilay@cs.wisc.edu    {
33010447Snilay@cs.wisc.edu        this->assign(1, c_);
33110447Snilay@cs.wisc.edu        return *this;
33210447Snilay@cs.wisc.edu    }
33310447Snilay@cs.wisc.edu
33410447Snilay@cs.wisc.edu    std::istream& safeGetline(std::istream& is_, String& str_)
33510447Snilay@cs.wisc.edu    {
33610447Snilay@cs.wisc.edu        str_.clear();
33710447Snilay@cs.wisc.edu
33810447Snilay@cs.wisc.edu        // The characters in the stream are read one-by-one using a std::streambuf.
33910447Snilay@cs.wisc.edu        // That is faster than reading them one-by-one using the std::istream.
34010447Snilay@cs.wisc.edu        // Code that uses streambuf this way must be guarded by a sentry object.
34110447Snilay@cs.wisc.edu        // The sentry object performs various tasks,
34210447Snilay@cs.wisc.edu        // such as thread synchronization and updating the stream state.
34310447Snilay@cs.wisc.edu
34410447Snilay@cs.wisc.edu        std::istream::sentry se(is_, true);
34510447Snilay@cs.wisc.edu        std::streambuf* sb = is_.rdbuf();
34610447Snilay@cs.wisc.edu
34710447Snilay@cs.wisc.edu        while(1)
34810447Snilay@cs.wisc.edu        {
34910447Snilay@cs.wisc.edu            int c = sb->sbumpc();
35010447Snilay@cs.wisc.edu            switch(c)
35110447Snilay@cs.wisc.edu            {
35210447Snilay@cs.wisc.edu                case '\r':
35310447Snilay@cs.wisc.edu                    c = sb->sgetc();
35410447Snilay@cs.wisc.edu                    if(c == '\n')
35510447Snilay@cs.wisc.edu                        sb->sbumpc();
35610447Snilay@cs.wisc.edu                    return is_;
35710447Snilay@cs.wisc.edu                case '\n':
35810447Snilay@cs.wisc.edu                    return is_;
35910447Snilay@cs.wisc.edu                case EOF:
36010447Snilay@cs.wisc.edu                    is_.setstate(std::ios_base::failbit|std::ios_base::eofbit);
36110447Snilay@cs.wisc.edu                    return is_;
36210447Snilay@cs.wisc.edu                default:
36310447Snilay@cs.wisc.edu                    str_ += String(1, (char)c);
36410447Snilay@cs.wisc.edu            }
36510447Snilay@cs.wisc.edu        }
36610447Snilay@cs.wisc.edu    }
36710447Snilay@cs.wisc.edu} // namespace LibUtil
36810447Snilay@cs.wisc.edu
369