Fix Windows compilation
[libs/core.git] / source / strings / utils.cpp
1 #include <algorithm>
2 #include <list>
3 #include <stdexcept>
4 #include <cctype>
5 #include "utils.h"
6
7 using namespace std;
8
9 namespace {
10
11 template<bool long_sep, bool allow_empty>
12 vector<string> do_split(const string &str, const string &sep, int max_split)
13 {
14         vector<string> result;
15
16         unsigned start = 0;
17         while(start<str.size())
18         {
19                 unsigned end = long_sep ? str.find(sep, start) : str.find_first_of(sep, start);
20                 if(end!=start || allow_empty)
21                 {
22                         if(max_split>=0 && result.size()==static_cast<unsigned>(max_split))
23                         {
24                                 result.push_back(str.substr(start));
25                                 break;
26                         }
27                         else
28                                 result.push_back(str.substr(start, end-start));
29                 }
30
31                 if(end>str.size())
32                         break;
33
34                 start = end+(long_sep ? sep.size() : 1);
35
36                 if(allow_empty && start==str.size())
37                         result.push_back(string());
38         }
39
40         return result;
41 }
42
43 bool check_str(const std::string &str, int (*pred)(int))
44 {
45         for(string::const_iterator i=str.begin(); i!=str.end(); ++i)
46                 if(!pred(*i))
47                         return false;
48         return true;
49 }
50
51 }
52
53
54 namespace Msp {
55
56 int strcasecmp(const string &s1, const string &s2)
57 {
58         string::const_iterator i1 = s1.begin();
59         string::const_iterator i2 = s2.begin();
60         for(; (i1!=s1.end() && i2!=s2.end()); ++i1, ++i2)
61         {
62                 const char c1 = ::tolower(*i1);
63                 const char c2 = ::tolower(*i2);
64                 if(c1!=c2) return c1-c2;
65         }
66         if(i1!=s1.end()) return *i1;
67         if(i2!=s2.end()) return -*i2;
68         return 0;
69 }
70
71 string tolower(const string &str)
72 {
73         string result(str);
74         transform(result.begin(), result.end(), result.begin(), ::tolower);
75         return result;
76 }
77
78 string toupper(const string &str)
79 {
80         string result(str);
81         transform(result.begin(), result.end(), result.begin(), ::toupper);
82         return result;
83 }
84
85 bool isnumrc(const string &str)
86 {
87         return check_str(str, isdigit);
88 }
89
90 bool isalpha(const string &str)
91 {
92         return check_str(str, isalpha);
93 }
94
95 bool isalnum(const string &str)
96 {
97         return check_str(str, isalnum);
98 }
99
100 vector<string> split(const string &str, const string &sep, int max_split)
101 {
102         return do_split<false, false>(str, sep, max_split);
103 }
104
105 vector<string> split(const string &str, char sep, int max_split)
106 {
107         return split(str, string(1, sep), max_split);
108 }
109
110 vector<string> split_long(const string &str, const string &sep, int max_split)
111 {
112         return do_split<true, false>(str, sep, max_split);
113 }
114
115 vector<string> split_fields(const string &str, const string &sep, int max_split)
116 {
117         return do_split<true, true>(str, sep, max_split);
118 }
119
120 vector<string> split_fields(const string &str, char sep, int max_split)
121 {
122         return split_fields(str, string(1, sep), max_split);
123 }
124
125 string strip(const string &s)
126 {
127         string result = s;
128         if(!result.erase(0, result.find_first_not_of(" \t\r\n")).empty())
129                 result.erase(result.find_last_not_of(" \t\r\n")+1);
130         return result;
131 }
132
133 string c_unescape(const std::string &str)
134 {
135         bool escape = false;
136         unsigned numeric_type = 0;
137         unsigned numeric_pos = 0;
138         unsigned numeric_value = 0;
139         string result;
140         for(string::const_iterator i=str.begin(); i!=str.end(); ++i)
141         {
142                 if(numeric_type==16)
143                 {
144                         unsigned digit = 0;
145                         if(*i>='0' && *i<='9')
146                                 digit = *i-'0';
147                         else if(*i>='a' && *i<='f')
148                                 digit = *i-'a'+10;
149                         else if(*i>='A' && *i<='F')
150                                 digit = *i-'A'+10;
151                         else
152                                 throw invalid_argument("c_unescape");
153
154                         numeric_value = (numeric_value<<4 | digit);
155                         ++numeric_pos;
156                         if(numeric_pos==2)
157                         {
158                                 result += numeric_value;
159                                 numeric_type = 0;
160                         }
161                 }
162                 else if(numeric_type==8)
163                 {
164                         unsigned digit = 0;
165                         if(*i>='0' && *i<='7')
166                                 digit = *i-'0';
167                         else
168                                 throw invalid_argument("c_unescape");
169
170                         numeric_value = (numeric_value<<3 | digit);
171                         ++numeric_pos;
172                         if(numeric_pos==3)
173                         {
174                                 result += numeric_value;
175                                 numeric_type = 0;
176                         }
177                 }
178                 else if(escape)
179                 {
180                         if(*i=='x')
181                         {
182                                 numeric_type = 16;
183                                 numeric_pos = 0;
184                                 numeric_value = 0;
185                         }
186                         else if(*i>='0' && *i<='3')
187                         {
188                                 numeric_type = 8;
189                                 numeric_pos = 1;
190                                 numeric_value = *i-'0';
191                         }
192                         else if(*i=='n')
193                                 result += '\n';
194                         else if(*i=='t')
195                                 result += '\t';
196                         else if(*i=='r')
197                                 result += '\r';
198                         else if(*i=='b')
199                                 result += '\b';
200                         else if(*i=='v')
201                                 result += '\v';
202                         else if(*i=='a')
203                                 result += '\a';
204                         else if(*i=='f')
205                                 result += '\f';
206                         else if(*i=='\"')
207                                 result += '\"';
208                         else if(*i=='\'')
209                                 result += '\'';
210                         else if(*i=='\\')
211                                 result += '\\';
212                         else
213                                 throw invalid_argument("c_unescape");
214
215                         escape = false;
216                 }
217                 else if(*i=='\\')
218                         escape = true;
219                 else
220                         result += *i;
221         }
222
223         if(escape)      
224                 throw invalid_argument("c_unescape");
225
226         return result;
227 }
228
229 string c_escape(const string &str, bool escape_8bit)
230 {
231         string result;
232
233         for(string::const_iterator i=str.begin(); i!=str.end(); ++i)
234         {
235                 if(*i=='\n')
236                         result += "\\n";
237                 else if(*i=='\t')
238                         result += "\\t";
239                 else if(*i=='\r')
240                         result += "\\r";
241                 else if(*i=='\b')
242                         result += "\\b";
243                 else if(*i=='\v')
244                         result += "\\v";
245                 else if(*i=='\a')
246                         result += "\\a";
247                 else if(*i=='\f')
248                         result += "\\f";
249                 else if(*i=='\"')
250                         result += "\\\"";
251                 else if(*i=='\'')
252                         result += "\\\'";
253                 else if(*i=='\\')
254                         result += "\\\\";
255                 else if(static_cast<unsigned char>(*i)<' ' || (escape_8bit && (*i&0x80)))
256                 {
257                         char buf[4] = { '\\', 0 };
258                         for(unsigned j=0; j<3; ++j)
259                                 buf[1+j] = '0'+((static_cast<unsigned char>(*i)>>(6-j*3))&7);
260                         result.append(buf, 4);
261                 }
262                 else
263                         result += *i;
264         }
265
266         return result;
267 }
268
269 } // namespace Msp