]> git.tdb.fi Git - libs/core.git/blob - source/utils.cpp
d67cc7e8bcd3947f62947be762af28aa60bf3f30
[libs/core.git] / source / utils.cpp
1 /* $Id$
2
3 This file is part of libmspstrings
4 Copyright © 2006-2007 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 }
50
51 namespace Msp {
52
53 int strcasecmp(const string &s1, const string &s2)
54 {
55         string::const_iterator i1=s1.begin();
56         string::const_iterator i2=s2.begin();
57         for(; (i1!=s1.end() && i2!=s2.end()); ++i1, ++i2)
58         {
59                 const char c1=::tolower(*i1);
60                 const char c2=::tolower(*i2);
61                 if(c1!=c2) return c1-c2;
62         }
63         if(i1!=s1.end()) return *i1;
64         if(i2!=s2.end()) return -*i2;
65         return 0;
66 }
67
68 string tolower(const string &str)
69 {
70         string result(str);
71         transform(result.begin(), result.end(), result.begin(), ::tolower);
72         return result;
73 }
74
75 string toupper(const string &str)
76 {
77         string result(str);
78         transform(result.begin(), result.end(), result.begin(), ::toupper);
79         return result;
80 }
81
82 vector<string> split(const string &str, const string &sep, int max_split)
83 {
84         return do_split<false, false>(str, sep, max_split);
85 }
86
87 vector<string> split(const string &str, char sep, int max_split)
88 {
89         return split(str, string(1, sep), max_split);
90 }
91
92 vector<string> split_long(const string &str, const string &sep, int max_split)
93 {
94         return do_split<true, false>(str, sep, max_split);
95 }
96
97 vector<string> split_fields(const string &str, const string &sep, int max_split)
98 {
99         return do_split<true, true>(str, sep, max_split);
100 }
101
102 vector<string> split_fields(const string &str, char sep, int max_split)
103 {
104         return split_fields(str, string(1, sep), max_split);
105 }
106
107 /**
108 Splits a string to parts.
109
110 @param   str          String to be split
111 @param   sep          A set of separator characters
112 @param   allow_empty  Whether or not to produce empty parts for sequences of
113                       more than one separator character
114 */
115 vector<string> split(const string &str, const string &sep, bool allow_empty)
116 {
117         vector<string> result;
118         
119         unsigned start=0;
120         if(!allow_empty)
121                 start=str.find_first_not_of(sep);
122         
123         while(start<str.size())
124         {
125                 unsigned end=str.find_first_of(sep, start);
126                 result.push_back(str.substr(start, end-start));
127                 
128                 if(end==string::npos)
129                         break;
130                 
131                 if(allow_empty)
132                 {
133                         start=end+1;
134                         if(start==str.size())
135                                 result.push_back(string());
136                 }
137                 else
138                         start=str.find_first_not_of(sep, end);
139         }
140
141         return result;
142 }
143
144 vector<string> split(const string &str, char sep, bool allow_empty)
145 {
146         return split(str, string(1, sep), allow_empty);
147 }
148
149 string strip(const string &s)
150 {
151         string result=s;
152         if(!result.erase(0, result.find_first_not_of(" \t\r\n")).empty())
153                 result.erase(result.find_last_not_of(" \t\r\n")+1);
154         return result;
155 }
156
157 string c_unescape(const std::string &str)
158 {
159         bool escape=false;
160         unsigned numeric_type=0;
161         unsigned numeric_pos=0;
162         unsigned numeric_value=0;
163         string result;
164         for(string::const_iterator i=str.begin(); i!=str.end(); ++i)
165         {
166                 if(numeric_type==16)
167                 {
168                         unsigned digit=0;
169                         if(*i>='0' && *i<='9')
170                                 digit=*i-'0';
171                         else if(*i>='a' && *i<='f')
172                                 digit=*i-'a'+10;
173                         else if(*i>='A' && *i<='F')
174                                 digit=*i-'A'+10;
175                         else
176                                 throw InvalidParameterValue("Invalid hexadecimal digit");
177
178                         numeric_value=(numeric_value<<4 | digit);
179                         ++numeric_pos;
180                         if(numeric_pos==2)
181                         {
182                                 result+=numeric_value;
183                                 numeric_type=0;
184                         }
185                 }
186                 else if(numeric_type==8)
187                 {
188                         unsigned digit=0;
189                         if(*i>='0' && *i<='7')
190                                 digit=*i-'0';
191                         else
192                                 throw InvalidParameterValue("Invalid octal digit");
193
194                         numeric_value=(numeric_value<<3 | digit);
195                         ++numeric_pos;
196                         if(numeric_pos==3)
197                         {
198                                 result+=numeric_value;
199                                 numeric_type=0;
200                         }
201                 }
202                 else if(escape)
203                 {
204                         if(*i=='x')
205                         {
206                                 numeric_type=16;
207                                 numeric_pos=0;
208                                 numeric_value=0;
209                         }
210                         else if(*i>='0' && *i<='3')
211                         {
212                                 numeric_type=8;
213                                 numeric_pos=1;
214                                 numeric_value=*i-'0';
215                         }
216                         else if(*i=='n')
217                                 result+='\n';
218                         else if(*i=='t')
219                                 result+='\t';
220                         else if(*i=='r')
221                                 result+='\r';
222                         else if(*i=='b')
223                                 result+='\b';
224                         else if(*i=='v')
225                                 result+='\v';
226                         else if(*i=='a')
227                                 result+='\a';
228                         else if(*i=='f')
229                                 result+='\f';
230                         else if(*i=='\"')
231                                 result+='\"';
232                         else if(*i=='\'')
233                                 result+='\'';
234                         else if(*i=='\\')
235                                 result+='\\';
236                         else
237                                 throw InvalidParameterValue("Invalid escape sequence");
238
239                         escape=false;
240                 }
241                 else if(*i=='\\')
242                         escape=true;
243                 else
244                         result+=*i;
245         }
246
247         if(escape)      
248                 throw InvalidParameterValue("Stray backslash at end of string");
249
250         return result;
251 }
252
253 string c_escape(const string &str, bool escape_8bit)
254 {
255         string result;
256
257         for(string::const_iterator i=str.begin(); i!=str.end(); ++i)
258         {
259                 if(*i=='\n')
260                         result+="\\n";
261                 else if(*i=='\t')
262                         result+="\\t";
263                 else if(*i=='\r')
264                         result+="\\r";
265                 else if(*i=='\b')
266                         result+="\\b";
267                 else if(*i=='\v')
268                         result+="\\v";
269                 else if(*i=='\a')
270                         result+="\\a";
271                 else if(*i=='\f')
272                         result+="\\f";
273                 else if(*i=='\"')
274                         result+="\\\"";
275                 else if(*i=='\'')
276                         result+="\\\'";
277                 else if(*i=='\\')
278                         result+="\\\\";
279                 else if(static_cast<unsigned char>(*i)<' ' || (escape_8bit && (*i&0x80)))
280                 {
281                         char buf[4]={'\\', '0'+((*i>>6)&7), '0'+((*i>>3)&7), '0'+(*i&7)};
282                         result.append(buf, 4);
283                 }
284                 else
285                         result+=*i;
286         }
287
288         return result;
289 }
290
291 } // namespace Msp