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