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