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