src/str.cxx

changeset 72
03e4d9db3fd9
parent 71
11f23fabf8a6
child 73
1ee9b312dc18
equal deleted inserted replaced
71:11f23fabf8a6 72:03e4d9db3fd9
1 /* 1 #include <cstring>
2 * botc source code 2 #include "main.h"
3 * Copyright (C) 2012 Santeri `Dusk` Piippo
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 * 3. Neither the name of the developer nor the names of its contributors may
15 * be used to endorse or promote products derived from this software without
16 * specific prior written permission.
17 * 4. Redistributions in any form must be accompanied by information on how to
18 * obtain complete source code for the software and any accompanying
19 * software that uses the software. The source code must either be included
20 * in the distribution or be available for no more than the cost of
21 * distribution plus a nominal fee, and must be freely redistributable
22 * under reasonable conditions. For an executable file, complete source
23 * code means the source code for all modules it contains. It does not
24 * include source code for modules or files that typically accompany the
25 * major components of the operating system on which the executable file
26 * runs.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
32 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 */
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <stdarg.h>
45 #include "array.h"
46 #include "str.h" 3 #include "str.h"
47 #include "common.h" 4
48 5 // =============================================================================
49 #define ITERATE_STRING(u) \ 6 //
50 for (unsigned int u = 0; u < strlen (text); u++) 7 int string::compare (const string& other) const
51 8 {
52 // ============================================================================ 9 return m_string.compare (other.std_string());
53 // vdynformat: Try to write to a formatted string with size bytes first, if 10 }
54 // that fails, double the size and keep recursing until it works. 11
55 char* vdynformat (const char* c, va_list v, unsigned int size) { 12 // =============================================================================
56 char* buffer = new char[size]; 13 //
57 int r = vsnprintf (buffer, size-1, c, v); 14 void string::trim (string::length_type n)
58 if (r > (int)size-1 || r < 0) { 15 {
59 delete buffer; 16 if (n > 0)
60 buffer = vdynformat (c, v, size*2); 17 m_string = substring (0, length() - n).std_string();
61 } 18 else
62 return buffer; 19 m_string = substring (n, -1).std_string();
63 } 20 }
64 21
65 // ============================================================================ 22 // =============================================================================
66 str::str () { 23 //
67 text = new char[1]; 24 string string::strip (list<char> unwanted)
68 clear(); 25 {
69 alloclen = strlen (text); 26 string copy (m_string);
70 } 27
71 28 for (char c : unwanted)
72 str::str (const char* c) { 29 for (int i = 0; i < copy.length(); ++i)
73 text = new char[1]; 30 if (copy[i] == c)
74 clear (); 31 copy.erase (i);
75 alloclen = strlen (text); 32
76 append (c); 33 /*
77 } 34 while(( pos = copy.first( c )) != -1 )
78 35 copy.erase( pos );
79 str::str (char c) { 36 */
80 text = new char[1]; 37
81 clear (); 38 return copy;
82 alloclen = strlen (text); 39 }
83 append (c); 40
84 } 41 // =============================================================================
85 42 //
86 // ============================================================================ 43 string string::to_uppercase() const
87 void str::clear () { 44 {
88 delete text; 45 string newstr = m_string;
89 text = new char[1]; 46
90 text[0] = '\0'; 47 for (char& c : newstr)
91 curs = 0; 48 if (c >= 'a' && c <= 'z')
92 } 49 c -= 'a' - 'A';
93 50
94 unsigned int str::len () {return strlen(text);} 51 return newstr;
95 52 }
96 // ============================================================================ 53
97 void str::resize (unsigned int len) { 54 // =============================================================================
98 unsigned int oldlen = strlen (text); 55 //
99 char* oldtext = new char[oldlen]; 56 string string::to_lowercase() const
100 strncpy (oldtext, text, oldlen); 57 {
101 58 string newstr = m_string;
102 delete text; 59
103 text = new char[len+1]; 60 for (char & c : newstr)
104 for (unsigned int u = 0; u < len+1; u++) 61 if (c >= 'A' && c <= 'Z')
105 text[u] = 0; 62 c += 'a' - 'A';
106 strncpy (text, oldtext, len); 63
107 64 return newstr;
108 alloclen = len; 65 }
109 } 66
110 67 // =============================================================================
111 // ============================================================================ 68 //
112 void str::dump () { 69 string_list string::split (char del) const
113 for (unsigned int u = 0; u <= alloclen; u++) 70 {
114 printf ("\t%u. %u (%c)\n", u, text[u], text[u]); 71 string delimstr;
115 } 72 delimstr += del;
116 73 return split (delimstr);
117 // ============================================================================ 74 }
118 // Adds a new character at the end of the string. 75
119 void str::append (char c) { 76 // =============================================================================
120 // Out of space, thus resize 77 //
121 if (curs == alloclen) 78 string_list string::split (string del) const
122 resize (alloclen+1); 79 {
123 text[curs] = c; 80 string_list res;
124 curs++; 81 long a = 0;
125 } 82
126 83 // Find all separators and store the text left to them.
127 void str::append (const char* c) { 84 for (;;)
128 resize (alloclen + strlen (c)); 85 {
129 86 long b = first (del, a);
130 for (unsigned int u = 0; u < strlen (c); u++) { 87
131 if (c[u] != 0) 88 if (b == -1)
132 append (c[u]); 89 break;
133 } 90
134 } 91 string sub = substring (a, b);
135 92
136 void str::append (str c) { 93 if (sub.length() > 0)
137 append (c.chars()); 94 res.push_back (substring (a, b));
138 } 95
139 96 a = b + strlen (del);
140 // ============================================================================ 97 }
141 void str::appendformat (const char* c, ...) { 98
142 va_list v; 99 // Add the string at the right of the last separator
143 100 if (a < (int) length())
144 va_start (v, c); 101 res.push_back (substring (a, length()));
145 char* buf = vdynformat (c, v, 256); 102
146 va_end (v); 103 return res;
147 104 }
148 append (buf); 105
149 } 106 // =============================================================================
150 107 //
151 void str::appendformat (str c, ...) { 108 void string::replace (const char* a, const char* b)
152 va_list v; 109 {
153 110 long pos;
154 va_start (v, c); 111
155 char* buf = vdynformat (c.chars(), v, 256); 112 while ( (pos = first (a)) != -1)
156 va_end (v); 113 m_string = m_string.replace (pos, strlen (a), b);
157 114 }
158 append (buf); 115
159 } 116 // =============================================================================
160 117 //
161 // ============================================================================ 118 int string::count (const char needle) const
162 char* str::chars () { 119 {
163 return text; 120 int numNeedles = 0;
164 } 121
165 122 for (const char & c : m_string)
166 // ============================================================================ 123 if (c == needle)
167 unsigned int str::first (const char* c, unsigned int a) { 124 numNeedles++;
168 unsigned int r = 0; 125
169 unsigned int index = 0; 126 return numNeedles;
170 for (; a < alloclen; a++) { 127 }
171 if (text[a] == c[r]) { 128
172 if (r == 0) 129 // =============================================================================
173 index = a; 130 //
174 131 string string::substring (long a, long b) const
175 r++; 132 {
176 if (r == strlen (c)) 133 if (b == -1)
177 return index; 134 b = length();
178 } else { 135
179 if (r != 0) { 136 if (b == a)
180 // If the string sequence broke at this point, we need to 137 return "";
181 // check this character again, for a new sequence just 138
182 // might start right here. 139 if (b < a)
183 a--; 140 {
184 } 141 // Swap the variables
185 142 int c = a;
186 r = 0; 143 a = b;
187 } 144 b = c;
188 } 145 }
189 146
190 return len (); 147 char* newString = new char[b - a + 1];
191 } 148 strncpy (newString, m_string.c_str() + a, b - a);
192 149 newString[b - a] = '\0';
193 // ============================================================================ 150
194 unsigned int str::last (const char* c, int a) { 151 string other (newString);
195 if (a == -1) 152 delete[] newString;
196 a = len(); 153 return other;
197 154 }
198 int max = strlen (c)-1; 155
199 156 // =============================================================================
200 int r = max; 157 //
201 for (; a >= 0; a--) { 158 string::length_type string::posof (int n) const
202 if (text[a] == c[r]) { 159 {
203 r--; 160 int count = 0;
204 if (r == -1) 161
205 return a; 162 for (int i = 0; i < length(); ++i)
206 } else { 163 {
207 if (r != max) 164 if (m_string[i] != ' ')
208 a++; 165 continue;
209 166
210 r = max; 167 if (++count < n)
211 } 168 continue;
212 } 169
213 170 return i;
214 return len (); 171 }
215 } 172
216 173 return -1;
217 // ============================================================================ 174 }
218 str str::substr (unsigned int a, unsigned int b) { 175
219 if (a > len()) a = len(); 176 // =============================================================================
220 if (b > len()) b = len(); 177 //
221 178 int string::first (const char* c, string::length_type a) const
222 if (b == a) 179 {
223 return ""; 180 for (; a < length(); a++)
224 181 if (m_string[a] == c[0] && strncmp (m_string.c_str() + a, c, strlen (c)) == 0)
225 if (b < a) { 182 return a;
226 printf ("str::substr: indices %u and %u given, should be the other way around, swapping..\n", a, b); 183
227 184 return -1;
228 // Swap the variables 185 }
229 unsigned int c = a; 186
230 a = b; 187 // =============================================================================
231 b = c; 188 //
232 } 189 int string::last (const char* c, string::length_type a) const
233 190 {
234 char* s = new char[b-a]; 191 if (a == -1 || a >= length())
235 strncpy (s, text+a, b-a); 192 a = length() - 1;
236 return str(s); 193
237 } 194 for (; a > 0; a--)
238 195 if (m_string[a] == c[0] && strncmp (m_string.c_str() + a, c, strlen (c)) == 0)
239 // ============================================================================ 196 return a;
240 void str::remove (unsigned int idx, unsigned int dellen) { 197
241 str s1 = substr (0, idx); 198 return -1;
242 str s2 = substr (idx + dellen, len()); 199 }
243 200
244 clear(); 201 // =============================================================================
245 202 //
246 append (s1); 203 void string::dump() const
247 append (s2); 204 {
248 } 205 print ("`%1`:\n", chars());
249 206 int i = 0;
250 // ============================================================================ 207
251 void str::trim (int dellen) { 208 for (char u : m_string)
252 if (!dellen) 209 print ("\t%1. [%d2] `%3`\n", i++, u, string (u));
253 return; 210 }
254 211
255 unsigned int delpos; 212 // =============================================================================
256 if (dellen > 0) { 213 //
257 delpos = len()-dellen; 214 long string::to_long (bool* ok, int base) const
258 text[delpos] = 0; 215 {
259 curs -= dellen; 216 errno = 0;
260 } else { 217 char* endptr;
261 str s = substr (-dellen, len()); 218 long i = strtol (m_string.c_str(), &endptr, base);
262 clear(); 219 *ok = (errno == 0 && *endptr == '\0');
263 append (s); 220 return i;
264 } 221 }
265 } 222
266 223 // =============================================================================
267 // ============================================================================ 224 //
268 void str::replace (const char* o, const char* n, unsigned int a) { 225 float string::to_float (bool* ok) const
269 unsigned int idx; 226 {
270 227 errno = 0;
271 while ((idx = first (o, a)) != len()) { 228 char* endptr;
272 str s1 = substr (0, idx); 229 float i = strtof (m_string.c_str(), &endptr);
273 str s2 = substr (idx + strlen (o), len()); 230 *ok = (errno == 0 && *endptr == '\0');
274 231 return i;
275 clear(); 232 }
276 233
277 append (s1); 234 // =============================================================================
278 append (n); 235 //
279 append (s2); 236 double string::to_double (bool* ok) const
280 } 237 {
281 } 238 errno = 0;
282 239 char* endptr;
283 void str::insert (char* c, unsigned int pos) { 240 double i = strtod (m_string.c_str(), &endptr);
284 str s1 = substr (0, pos); 241 *ok = (errno == 0 && *endptr == '\0');
285 str s2 = substr (pos, len()); 242 return i;
286 243 }
287 clear(); 244
288 append (s1); 245 // =============================================================================
289 append (c); 246 //
290 append (s2); 247 bool operator== (const char* a, const string& b)
291 } 248 {
292 249 return b == a;
293 void str::reverse () { 250 }
294 char* tmp = new char[alloclen]; 251
295 strcpy (tmp, text); 252 // =============================================================================
296 253 //
297 clear(); 254 string operator+ (const char* a, const string& b)
298 curs = 0; 255 {
299 resize (alloclen); 256 return string (a) + b;
300 for (int i = alloclen-1; i >= 0; i--) 257 }
301 append (tmp[i]); 258
302 } 259 // =============================================================================
303 260 //
304 void str::repeat (unsigned int n) { 261 string string::operator+ (const string data) const
305 char* tmp = new char[alloclen]; 262 {
306 strcpy (tmp, text); 263 string newString = *this;
307 264 newString += data;
308 for (; n > 0; n--) 265 return newString;
309 append (tmp); 266 }
310 } 267
311 268 // =============================================================================
312 // ============================================================================ 269 //
313 bool str::isnumber () { 270 string string::operator+ (const char* data) const
314 ITERATE_STRING (u) { 271 {
315 // Minus sign as the first character is allowed for negatives 272 string newString = *this;
316 if (!u && text[u] == '-') 273 newString += data;
317 continue; 274 return newString;
318 275 }
319 if (text[u] < '0' || text[u] > '9') 276
320 return false; 277 // =============================================================================
321 } 278 //
322 return true; 279 string& string::operator+= (const string data)
323 } 280 {
324 281 append (data);
325 // ============================================================================ 282 return *this;
326 bool str::isword () { 283 }
327 ITERATE_STRING (u) { 284
328 // lowercase letters 285 // =============================================================================
329 if (text[u] >= 'a' || text[u] <= 'z') 286 //
330 continue; 287 string& string::operator+= (const char* data)
331 288 {
332 // uppercase letters 289 append (data);
333 if (text[u] >= 'A' || text[u] <= 'Z') 290 return *this;
334 continue; 291 }
335 292
336 return false; 293 // =============================================================================
337 } 294 //
338 return true; 295 bool string::is_numeric() const
339 } 296 {
340 297 bool gotDot = false;
341 // ============================================================================ 298
342 int str::compare (const char* c) { 299 for (const char & c : m_string)
343 return strcmp (text, c); 300 {
344 } 301 // Allow leading hyphen for negatives
345 302 if (&c == &m_string[0] && c == '-')
346 int str::compare (str c) { 303 continue;
347 return compare (c.chars()); 304
348 } 305 // Check for decimal point
349 306 if (!gotDot && c == '.')
350 int str::icompare (const char* c) { 307 {
351 return icompare (str ((char*)c)); 308 gotDot = true;
352 } 309 continue;
353 310 }
354 int str::icompare (str b) { 311
355 return strcmp (tolower().chars(), b.tolower().chars()); 312 if (c >= '0' && c <= '9')
356 } 313 continue; // Digit
357 314
358 // ============================================================================ 315 // If the above cases didn't catch this character, it was
359 str str::tolower () { 316 // illegal and this is therefore not a number.
360 str n = text; 317 return false;
361 318 }
362 for (uint u = 0; u < len(); u++) { 319
363 if (n[u] > 'A' && n[u] < 'Z') 320 return true;
364 n.text[u] += ('a' - 'A'); 321 }
365 } 322
366 323 // =============================================================================
367 return n; 324 //
368 } 325 bool string::ends_with (const string& other)
369 326 {
370 // ============================================================================ 327 if (length() < other.length())
371 str str::toupper () { 328 return false;
372 str n = text; 329
373 330 const int ofs = length() - other.length();
374 for (uint u = 0; u < len(); u++) { 331 return strncmp (chars() + ofs, other.chars(), other.length()) == 0;
375 if (n[u] > 'a' && n[u] < 'z') 332 }
376 n.text[u] -= ('A' - 'a'); 333
377 } 334 // =============================================================================
378 335 //
379 return n; 336 bool string::starts_with (const string& other)
380 } 337 {
381 338 if (length() < other.length())
382 // ============================================================================ 339 return false;
383 unsigned int str::count (char* c) { 340
384 unsigned int r = 0; 341 return strncmp (chars(), other.chars(), other.length()) == 0;
385 unsigned int tmp = 0; 342 }
386 ITERATE_STRING (u) { 343
387 if (text[u] == c[r]) { 344 // =============================================================================
388 r++; 345 //
389 if (r == strlen (c)) { 346 void string::sprintf (const char* fmtstr, ...)
390 r = 0; 347 {
391 tmp++; 348 char* buf;
392 } 349 int bufsize = 256;
393 } else { 350 va_list va;
394 if (r != 0) 351 va_start (va, fmtstr);
395 u--; 352
396 r = 0; 353 do
397 } 354 buf = new char[bufsize];
398 } 355
399 356 while (vsnprintf (buf, bufsize, fmtstr, va) >= bufsize);
400 return tmp; 357
401 } 358 va_end (va);
402 359 m_string = buf;
403 // ============================================================================ 360 delete[] buf;
404 array<str> str::split (str del) { 361 }
405 array<str> res; 362
406 unsigned int a = 0; 363 // =============================================================================
407 364 //
408 // Find all separators and store the text left to them. 365 void string::prepend (string a)
409 while (1) { 366 {
410 unsigned int b = first (del, a); 367 m_string = (a + m_string).std_string();
411 368 }
412 if (b == len()) 369
413 break; 370 // =============================================================================
414 371 //
415 res.push (substr (a, b)); 372 string string_list::join (const string& delim)
416 a = b + strlen (del); 373 {
417 } 374 string result;
418 375
419 // Add the string at the right of the last separator 376 for (const string & it : std_deque())
420 res.push (substr (a, len())); 377 {
421 return res; 378 if (!result.is_empty())
422 } 379 result += delim;
423 380
424 array<str> str::operator/ (str splitstring) {return split(splitstring);} 381 result += it;
425 array<str> str::operator/ (char* splitstring) {return split(splitstring);} 382 }
426 array<str> str::operator/ (const char* splitstring) {return split(splitstring);} 383
384 return result;
385 }
386
387 // =============================================================================
388 //
389 bool string::mask (const string& pattern) const
390 {
391 // Elevate to uppercase for case-insensitive matching
392 string pattern_upper = pattern.to_uppercase();
393 string this_upper = to_uppercase();
394 const char* maskstring = pattern_upper.chars();
395 const char* mptr = &maskstring[0];
396
397 for (const char* sptr = this_upper.chars(); *sptr != '\0'; sptr++)
398 {
399 if (*mptr == '?')
400 {
401 if (* (sptr + 1) == '\0')
402 {
403 // ? demands that there's a character here and there wasn't.
404 // Therefore, mask matching fails
405 return false;
406 }
407 }
408
409 elif (*mptr == '*')
410 {
411 char end = * (++mptr);
412
413 // If '*' is the final character of the message, all of the remaining
414 // string matches against the '*'. We don't need to bother checking
415 // the string any further.
416 if (end == '\0')
417 return true;
418
419 // Skip to the end character
420 while (*sptr != end && *sptr != '\0')
421 sptr++;
422
423 // String ended while the mask still had stuff
424 if (*sptr == '\0')
425 return false;
426 }
427 elif (*sptr != *mptr)
428 return false;
429
430 mptr++;
431 }
432
433 return true;
434 }

mercurial