]> git.mxchange.org Git - simgear.git/blob - simgear/misc/strutils.cxx
Merge branch 'next' of git://gitorious.org/fg/simgear into next
[simgear.git] / simgear / misc / strutils.cxx
1 // String utilities.
2 //
3 // Written by Bernie Bright, started 1998
4 //
5 // Copyright (C) 1998  Bernie Bright - bbright@bigpond.net.au
6 //
7 // This library is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU Library General Public
9 // License as published by the Free Software Foundation; either
10 // version 2 of the License, or (at your option) any later version.
11 //
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // Library General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21 // $Id$
22
23 #include <ctype.h>
24 #include <cstring>
25 #include <sstream>
26
27 #include "strutils.hxx"
28
29 using std::string;
30 using std::vector;
31 using std::stringstream;
32
33 namespace simgear {
34     namespace strutils {
35
36         /**
37          * 
38          */
39         static vector<string>
40         split_whitespace( const string& str, int maxsplit )
41         {
42             vector<string> result;
43             string::size_type len = str.length();
44             string::size_type i = 0;
45             string::size_type j;
46             int countsplit = 0;
47
48             while (i < len)
49             {
50                 while (i < len && isspace((unsigned char)str[i]))
51                 {
52                     ++i;
53                 }
54
55                 j = i;
56
57                 while (i < len && !isspace((unsigned char)str[i]))
58                 {
59                     ++i;
60                 }
61
62                 if (j < i)
63                 {
64                     result.push_back( str.substr(j, i-j) );
65                     ++countsplit;
66                     while (i < len && isspace((unsigned char)str[i]))
67                     {
68                         ++i;
69                     }
70
71                     if (maxsplit && (countsplit >= maxsplit) && i < len)
72                     {
73                         result.push_back( str.substr( i, len-i ) );
74                         i = len;
75                     }
76                 }
77             }
78
79             return result;
80         }
81
82         /**
83          * 
84          */
85         vector<string>
86         split( const string& str, const char* sep, int maxsplit )
87         {
88             if (sep == 0)
89                 return split_whitespace( str, maxsplit );
90
91             vector<string> result;
92             int n = std::strlen( sep );
93             if (n == 0)
94             {
95                 // Error: empty separator string
96                 return result;
97             }
98             const char* s = str.c_str();
99             string::size_type len = str.length();
100             string::size_type i = 0;
101             string::size_type j = 0;
102             int splitcount = 0;
103
104             while (i+n <= len)
105             {
106                 if (s[i] == sep[0] && (n == 1 || std::memcmp(s+i, sep, n) == 0))
107                 {
108                     result.push_back( str.substr(j,i-j) );
109                     i = j = i + n;
110                     ++splitcount;
111                     if (maxsplit && (splitcount >= maxsplit))
112                         break;
113                 }
114                 else
115                 {
116                     ++i;
117                 }
118             }
119
120             result.push_back( str.substr(j,len-j) );
121             return result;
122         }
123
124         /**
125          * The lstrip(), rstrip() and strip() functions are implemented
126          * in do_strip() which uses an additional parameter to indicate what
127          * type of strip should occur.
128          */
129         const int LEFTSTRIP = 0;
130         const int RIGHTSTRIP = 1;
131         const int BOTHSTRIP = 2;
132
133         static string
134         do_strip( const string& s, int striptype )
135         {
136             string::size_type len = s.length();
137             if( len == 0 ) // empty string is trivial
138                 return s;
139             string::size_type i = 0;
140             if (striptype != RIGHTSTRIP)
141             {
142                 while (i < len && isspace(s[i]))
143                 {
144                     ++i;
145                 }
146             }
147
148             string::size_type j = len;
149             if (striptype != LEFTSTRIP)
150             {
151                 do
152                 {
153                     --j;
154                 }
155                 while (j >= 1 && isspace(s[j]));
156                 ++j;
157             }
158
159             if (i == 0 && j == len)
160             {
161                 return s;
162             }
163             else
164             {
165                 return s.substr( i, j - i );
166             }
167         }
168
169         string
170         lstrip( const string& s )
171         {
172             return do_strip( s, LEFTSTRIP );
173         }
174
175         string
176         rstrip( const string& s )
177         {
178             return do_strip( s, RIGHTSTRIP );
179         }
180
181         string
182         strip( const string& s )
183         {
184             return do_strip( s, BOTHSTRIP );
185         }
186
187         string 
188         rpad( const string & s, string::size_type length, char c )
189         {
190             string::size_type l = s.length();
191             if( l >= length ) return s;
192             string reply = s;
193             return reply.append( length-l, c );
194         }
195
196         string 
197         lpad( const string & s, size_t length, char c )
198         {
199             string::size_type l = s.length();
200             if( l >= length ) return s;
201             string reply = s;
202             return reply.insert( 0, length-l, c );
203         }
204
205         bool
206         starts_with( const string & s, const string & substr )
207         {       
208                 return s.find( substr ) == 0;
209         }
210
211         bool
212         ends_with( const string & s, const string & substr )
213         {       
214                 size_t n = s.rfind( substr );
215                 return (n != string::npos) && (n == s.length() - substr.length());
216         }
217
218     string simplify(const string& s)
219     {
220         string result; // reserve size of 's'?
221         string::const_iterator it = s.begin(),
222             end = s.end();
223     
224     // advance to first non-space char - simplifes logic in main loop,
225     // since we can always prepend a single space when we see a 
226     // space -> non-space transition
227         for (; (it != end) && isspace(*it); ++it) { /* nothing */ }
228         
229         bool lastWasSpace = false;
230         for (; it != end; ++it) {
231             char c = *it;
232             if (isspace(c)) {
233                 lastWasSpace = true;
234                 continue;
235             }
236             
237             if (lastWasSpace) {
238                 result.push_back(' ');
239             }
240             
241             lastWasSpace = false;
242             result.push_back(c);
243         }
244         
245         return result;
246     }
247     
248     int to_int(const std::string& s, int base)
249     {
250         stringstream ss(s);
251         switch (base) {
252         case 8:      ss >> std::oct; break;
253         case 16:     ss >> std::hex; break;
254         default: break;
255         }
256         
257         int result;
258         ss >> result;
259         return result;
260     }
261     
262     int compare_versions(const string& v1, const string& v2)
263     {
264         vector<string> v1parts(split(v1, "."));
265         vector<string> v2parts(split(v2, "."));
266
267         int lastPart = std::min(v1parts.size(), v2parts.size());
268         for (int part=0; part < lastPart; ++part) {
269             int part1 = to_int(v1parts[part]);
270             int part2 = to_int(v2parts[part]);
271
272             if (part1 != part2) {
273                 return part1 - part2;
274             }
275         } // of parts iteration
276
277         // reached end - longer wins
278         return v1parts.size() - v2parts.size();
279     }
280     
281     
282     } // end namespace strutils
283     
284 } // end namespace simgear