1/* Copyright (c) 2012 Massachusetts Institute of Technology
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 * THE SOFTWARE.
20 */
21
22#include "String.h"
23
24#include <cstdarg>
25#include <cstdio>
26#include <iostream>
27#include <ios>
28
29namespace LibUtil
30{
31    const unsigned int String::msBufferSize = 4096;
32
33    String String::format(const String& format_, ...)
34    {
35        char buffer[msBufferSize];
36
37        va_list args;
38        va_start(args, format_);
39        vsnprintf(buffer, msBufferSize, format_.c_str(), args);
40        va_end(args);
41
42        return (String)(buffer);
43    }
44
45    String String::format(const String& format_, va_list args_)
46    {
47        char buffer[msBufferSize];
48
49        vsnprintf(buffer, msBufferSize, format_.c_str(), args_);
50
51        return (String)(buffer);
52    }
53
54    String::String()
55    {}
56
57    String::String(const string& str_)
58        : string(str_)
59    {}
60
61    String::String(const char* str_, size_t n_)
62        : string(str_, n_)
63    {}
64
65    String::String(const char* str_)
66        : string(str_)
67    {}
68
69    String::String(size_t n_, char c_)
70        : string(n_, c_)
71    {}
72
73    String::String(int value_)
74        : string(toString<int>(value_))
75    {}
76
77    String::String(unsigned int value_)
78        : string(toString<unsigned int>(value_))
79    {}
80
81    String::String(long value_)
82        : string(toString<long>(value_))
83    {}
84
85    String::String(unsigned long value_)
86        : string(toString<unsigned long>(value_))
87    {}
88
89    String::String(float value_)
90        : string(toString<float>(value_))
91    {}
92
93    String::String(double value_)
94        : string(toString<double>(value_))
95    {}
96
97    String::String(bool value_)
98        : string(toString<bool>(value_))
99    {}
100
101    String::~String()
102    {}
103
104    String& String::trim()
105    {
106        // Remove leading and trailing whitespace
107        static const char whitespace[] = " \n\t\v\r\f";
108        erase(0, find_first_not_of(whitespace));
109        erase(find_last_not_of(whitespace) + 1U);
110        return (*this);
111    }
112
113    String& String::substitute(const String& str1_, const String& str2_)
114    {
115        size_t str1Size = str1_.size();
116        size_t str2Size = str2_.size();
117
118        size_t pos;
119        pos = find(str1_);
120        while(pos != string::npos)
121        {
122            replace(pos, str1Size, str2_);
123            pos += str2Size;
124            pos = find(str1_, pos);
125        }
126        return (*this);
127    }
128
129    vector<String> String::split(const char* delimiters_) const
130    {
131        vector<String> result;
132
133        if(size() == 0)
134        {
135            return result;
136        }
137
138        size_t currPos, nextPos;
139        currPos = 0;
140        nextPos = find_first_of(delimiters_);
141        while(1)
142        {
143            if(nextPos == string::npos)
144            {
145                if(currPos != size())
146                {
147                    result.push_back(substr(currPos));
148                }
149                break;
150            }
151
152            if(nextPos != currPos)
153            {
154                result.push_back(substr(currPos, nextPos - currPos));
155            }
156            currPos = nextPos + 1;
157            nextPos = find_first_of(delimiters_, currPos);
158        }
159
160        return result;
161    }
162
163    vector<String> String::split(const String* delimiters_, unsigned int num_delimiters_) const
164    {
165        vector<String> result;
166
167        if(size() == 0)
168        {
169            return result;
170        }
171
172        if(num_delimiters_ == 1)
173        {
174            size_t currPos, nextPos;
175            currPos = 0;
176            nextPos = find(delimiters_[0]);
177            while(1)
178            {
179                if(nextPos == String::npos)
180                {
181                    result.push_back(substr(currPos));
182                    break;
183                }
184
185                if(nextPos != currPos)
186                {
187                    result.push_back(substr(currPos, nextPos - currPos));
188                }
189                currPos = nextPos + delimiters_[0].size();
190                nextPos = find(delimiters_[0], currPos);
191            }
192        }
193        else
194        {
195            // Currently the length of the delimiters are not checked
196            unsigned int delimiterLength = 0;
197            size_t currPos, nextPos;
198            currPos = 0;
199            nextPos = size();
200            for(unsigned int i = 0; i < num_delimiters_; ++i)
201            {
202                size_t tempPos = find(delimiters_[i], currPos);
203                if((tempPos != String::npos) && (tempPos < nextPos))
204                {
205                    nextPos = tempPos;
206                    delimiterLength = delimiters_[i].size();
207                }
208            }
209            while(1)
210            {
211                if((nextPos == String::npos) || (nextPos == size()))
212                {
213                    result.push_back(substr(currPos));
214                    break;
215                }
216
217                if(nextPos != currPos)
218                {
219                    result.push_back(substr(currPos, nextPos - currPos));
220                }
221                currPos = nextPos + delimiterLength;
222                nextPos = size();
223                delimiterLength = 0;
224                for(unsigned int i = 0; i < num_delimiters_; ++i)
225                {
226                    size_t tempPos = find(delimiters_[i], currPos);
227                    if((tempPos != String::npos) && (tempPos < nextPos))
228                    {
229                        nextPos = tempPos;
230                        delimiterLength = delimiters_[i].size();
231                    }
232                }
233            }
234        }
235        return result;
236    }
237
238    vector<String> String::splitByString(const String& delimiter_) const
239    {
240        return split(&delimiter_, 1);
241    }
242
243    bool String::contain(const String& str_) const
244    {
245        return (find(str_) != String::npos);
246    }
247
248    const char* String::toCString() const
249    {
250        return this->c_str();
251    }
252
253    int String::toInt() const
254    {
255        return fromString<int>(*this);
256    }
257
258    unsigned int String::toUInt() const
259    {
260        return fromString<unsigned int>(*this);
261    }
262
263    long String::toLong() const
264    {
265        return fromString<long>(*this);
266    }
267
268    unsigned long String::toULong() const
269    {
270        return fromString<unsigned long>(*this);
271    }
272
273    float String::toFloat() const
274    {
275        return fromString<float>(*this);
276    }
277
278    double String::toDouble() const
279    {
280        return fromString<double>(*this);
281    }
282
283    bool String::toBool() const
284    {
285        return fromString<bool>(*this);
286    }
287
288    String::operator const char*() const
289    {
290        return this->c_str();
291    }
292
293    String::operator int() const
294    {
295        return fromString<int>(*this);
296    }
297
298    String::operator unsigned int() const
299    {
300        return fromString<unsigned int>(*this);
301    }
302
303    String::operator long() const
304    {
305        return fromString<long>(*this);
306    }
307
308    String::operator unsigned long() const
309    {
310        return fromString<unsigned long>(*this);
311    }
312
313    String::operator float() const
314    {
315        return fromString<float>(*this);
316    }
317
318    String::operator double() const
319    {
320        return fromString<double>(*this);
321    }
322
323    String::operator bool() const
324    {
325        return fromString<bool>(*this);
326    }
327
328    String& String::operator=(char c_)
329    {
330        this->assign(1, c_);
331        return *this;
332    }
333
334    std::istream& safeGetline(std::istream& is_, String& str_)
335    {
336        str_.clear();
337
338        // The characters in the stream are read one-by-one using a std::streambuf.
339        // That is faster than reading them one-by-one using the std::istream.
340        // Code that uses streambuf this way must be guarded by a sentry object.
341        // The sentry object performs various tasks,
342        // such as thread synchronization and updating the stream state.
343
344        std::istream::sentry se(is_, true);
345        std::streambuf* sb = is_.rdbuf();
346
347        while(1)
348        {
349            int c = sb->sbumpc();
350            switch(c)
351            {
352                case '\r':
353                    c = sb->sgetc();
354                    if(c == '\n')
355                        sb->sbumpc();
356                    return is_;
357                case '\n':
358                    return is_;
359                case EOF:
360                    is_.setstate(std::ios_base::failbit|std::ios_base::eofbit);
361                    return is_;
362                default:
363                    str_ += String(1, (char)c);
364            }
365        }
366    }
367} // namespace LibUtil
368
369