]> git.tdb.fi Git - libs/core.git/blob - source/utils.cpp
Add documentation for all functions in utils
[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/error.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==1)
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==2)
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                         if(numeric_pos==0 && digit>3)
194                                 throw InvalidParameterValue("Octal escape sequence must start with [0-3]");
195
196                         numeric_value=(numeric_value<<3 | digit);
197                         ++numeric_pos;
198                         if(numeric_pos==2)
199                         {
200                                 result+=numeric_value;
201                                 numeric_type=0;
202                         }
203                 }
204                 else if(escape)
205                 {
206                         if(*i=='x' || (*i>='0' && *i<='7'))
207                         {
208                                 numeric_type=(*i=='x' ? 1 : 2);
209                                 numeric_pos=0;
210                                 numeric_value=0;
211                         }
212                         else if(*i=='n')
213                                 result+='\n';
214                         else if(*i=='t')
215                                 result+='\t';
216                         else if(*i=='r')
217                                 result+='\r';
218                         else if(*i=='b')
219                                 result+='\b';
220                         else if(*i=='v')
221                                 result+='\v';
222                         else if(*i=='a')
223                                 result+='\a';
224                         else if(*i=='f')
225                                 result+='\f';
226                         else if(*i=='\"')
227                                 result+='\"';
228                         else if(*i=='\'')
229                                 result+='\'';
230                         else if(*i=='\\')
231                                 result+='\\';
232                         else
233                                 throw InvalidParameterValue("Invalid escape sequence");
234
235                         escape=false;
236                 }
237                 else if(*i=='\\')
238                         escape=true;
239                 else
240                         result+=*i;
241         }
242
243         if(escape)      
244                 throw InvalidParameterValue("Stray backslash at end of string");
245
246         return result;
247 }
248
249 string c_escape(const string &str, bool escape_8bit)
250 {
251         string result;
252
253         for(string::const_iterator i=str.begin(); i!=str.end(); ++i)
254         {
255                 if(*i=='\n')
256                         result+="\\n";
257                 else if(*i=='\t')
258                         result+="\\t";
259                 else if(*i=='\r')
260                         result+="\\r";
261                 else if(*i=='\b')
262                         result+="\\b";
263                 else if(*i=='\v')
264                         result+="\\v";
265                 else if(*i=='\a')
266                         result+="\\a";
267                 else if(*i=='\f')
268                         result+="\\f";
269                 else if(*i=='\"')
270                         result+="\\\"";
271                 else if(*i=='\'')
272                         result+="\\\'";
273                 else if(*i=='\\')
274                         result+="\\\\";
275                 else if(*i<' ' || (escape_8bit && (*i&0x80)))
276                 {
277                         char buf[4]={'\\', (*i>>6)&7, (*i>>3)&7, *i&7};
278                         result.append(buf, 4);
279                 }
280                 else
281                         result+=*i;
282         }
283
284         return result;
285 }
286
287 } // namespace Msp