1/*-------------------------------------------------------------------------
2 * drawElements C++ Base Library
3 * -----------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief String utilities.
22 *//*--------------------------------------------------------------------*/
23
24#include "deStringUtil.hpp"
25#include "deString.h"
26
27#include <algorithm>
28#include <iterator>
29#include <sstream>
30#include <locale>
31#include <iomanip>
32#include <cctype>
33
34using std::locale;
35using std::string;
36using std::vector;
37using std::istringstream;
38using std::istream_iterator;
39
40namespace de
41{
42namespace
43{
44
45// Always use locale::classic to ensure consistent behavior in all environments.
46
47struct ToLower
48{
49	const locale&	loc;
50					ToLower		(void) : loc(locale::classic()) {}
51	char			operator()	(char c) { return std::tolower(c, loc); }
52};
53
54struct ToUpper
55{
56	const locale&	loc;
57					ToUpper		(void) : loc(locale::classic()) {}
58	char			operator()	(char c) { return std::toupper(c, loc); }
59};
60
61} // anonymous
62
63//! Convert string to lowercase using the classic "C" locale
64string toLower (const string& str)
65{
66	string ret;
67	std::transform(str.begin(), str.end(), std::inserter(ret, ret.begin()), ToLower());
68	return ret;
69}
70
71//! Convert string to uppercase using the classic "C" locale
72string toUpper (const string& str)
73{
74	string ret;
75	std::transform(str.begin(), str.end(), std::inserter(ret, ret.begin()), ToUpper());
76	return ret;
77}
78
79//! Convert string's first character to uppercase using the classic "C" locale
80string capitalize (const string& str)
81{
82	if (str.empty())
83		return str;
84	return ToUpper()(str[0]) + str.substr(1);
85}
86
87//! Split a string into tokens. If `delim` is `'\0'`, separate by spans of
88//! whitespace. Otherwise use a single character `delim` as the separator.
89
90vector<string> splitString (const string& s, char delim)
91{
92	istringstream tokenStream(s);
93
94	if (delim == '\0')
95		return vector<string>(istream_iterator<string>(tokenStream),
96							  istream_iterator<string>());
97	else
98	{
99		vector<string>	ret;
100		string			token;
101
102		while (std::getline(tokenStream, token, delim))
103			ret.push_back(token);
104
105		return ret;
106	}
107}
108
109//! Convert floating-point value to string with fixed number of fractional decimals.
110std::string floatToString (float val, int precision)
111{
112	std::ostringstream s;
113	s << std::fixed << std::setprecision(precision) << val;
114	return s.str();
115}
116
117bool beginsWith (const std::string& s, const std::string& prefix)
118{
119	return deStringBeginsWith(s.c_str(), prefix.c_str()) == DE_TRUE;
120}
121
122bool endsWith (const std::string& s, const std::string& suffix)
123{
124	if (suffix.length() > s.length())
125		return false;
126	else
127	{
128		const std::string::size_type offset = s.length() - suffix.length();
129		return s.find(suffix, offset) == offset;
130	}
131}
132
133char toUpper (char c)
134{
135	return std::toupper(c, std::locale::classic());
136}
137
138char toLower (char c)
139{
140	return std::tolower(c, std::locale::classic());
141}
142
143bool isUpper (char c)
144{
145	return std::isupper(c, std::locale::classic());
146}
147
148bool isLower (char c)
149{
150	return std::islower(c, std::locale::classic());
151}
152
153bool isDigit (char c)
154{
155	return std::isdigit(c, std::locale::classic());
156}
157
158void StringUtil_selfTest (void)
159{
160
161	DE_TEST_ASSERT(toString(42) == "42");
162	DE_TEST_ASSERT(toString("foo") == "foo");
163	DE_TEST_ASSERT(toLower("FooBar") == "foobar");
164	DE_TEST_ASSERT(toUpper("FooBar") == "FOOBAR");
165
166	{
167		vector <string> tokens(splitString(" foo bar\n\tbaz   "));
168		DE_TEST_ASSERT(tokens.size() == 3);
169		DE_TEST_ASSERT(tokens[0] == "foo");
170		DE_TEST_ASSERT(tokens[1] == "bar");
171		DE_TEST_ASSERT(tokens[2] == "baz");
172	}
173
174	DE_TEST_ASSERT(floatToString(4, 1) == "4.0");
175
176	DE_TEST_ASSERT(beginsWith("foobar", "foobar"));
177	DE_TEST_ASSERT(beginsWith("foobar", "foo"));
178	DE_TEST_ASSERT(beginsWith("foobar", "f"));
179	DE_TEST_ASSERT(beginsWith("foobar", ""));
180	DE_TEST_ASSERT(beginsWith("", ""));
181	DE_TEST_ASSERT(!beginsWith("foobar", "bar"));
182	DE_TEST_ASSERT(!beginsWith("foobar", "foobarbaz"));
183	DE_TEST_ASSERT(!beginsWith("", "foo"));
184
185	DE_TEST_ASSERT(endsWith("foobar", "foobar"));
186	DE_TEST_ASSERT(endsWith("foobar", "bar"));
187	DE_TEST_ASSERT(endsWith("foobar", "r"));
188	DE_TEST_ASSERT(endsWith("foobar", ""));
189	DE_TEST_ASSERT(endsWith("", ""));
190	DE_TEST_ASSERT(!endsWith("foobar", "foo"));
191	DE_TEST_ASSERT(!endsWith("foobar", "bazfoobar"));
192	DE_TEST_ASSERT(!endsWith("foobar", "foobarbaz"));
193	DE_TEST_ASSERT(!endsWith("", "foo"));
194
195	DE_TEST_ASSERT(toUpper('a') == 'A');
196	DE_TEST_ASSERT(toUpper('A') == 'A');
197	DE_TEST_ASSERT(toLower('a') == 'a');
198	DE_TEST_ASSERT(toLower('A') == 'a');
199	DE_TEST_ASSERT(isUpper('A'));
200	DE_TEST_ASSERT(!isUpper('a'));
201	DE_TEST_ASSERT(isLower('a'));
202	DE_TEST_ASSERT(!isLower('A'));
203	DE_TEST_ASSERT(isDigit('0'));
204	DE_TEST_ASSERT(!isDigit('a'));
205}
206
207} // de
208