1 /* Copyright (c) 2003-2005, 2007 MySQL AB
2 Use is subject to license terms
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
16
17 /* -*- c-basic-offset: 4; -*- */
18 #include <ndb_global.h>
19 #include <BaseString.hpp>
20 #include "basestring_vsnprintf.h"
21
BaseString()22 BaseString::BaseString()
23 {
24 m_chr = new char[1];
25 if (m_chr == NULL)
26 {
27 errno = ENOMEM;
28 m_len = 0;
29 return;
30 }
31 m_chr[0] = 0;
32 m_len = 0;
33 }
34
BaseString(const char * s)35 BaseString::BaseString(const char* s)
36 {
37 if (s == NULL)
38 {
39 m_chr = NULL;
40 m_len = 0;
41 }
42 const size_t n = strlen(s);
43 m_chr = new char[n + 1];
44 if (m_chr == NULL)
45 {
46 errno = ENOMEM;
47 m_len = 0;
48 return;
49 }
50 memcpy(m_chr, s, n + 1);
51 m_len = n;
52 }
53
BaseString(const BaseString & str)54 BaseString::BaseString(const BaseString& str)
55 {
56 const char* const s = str.m_chr;
57 const size_t n = str.m_len;
58 if (s == NULL)
59 {
60 m_chr = NULL;
61 m_len = 0;
62 return;
63 }
64 char* t = new char[n + 1];
65 if (t == NULL)
66 {
67 errno = ENOMEM;
68 m_chr = NULL;
69 m_len = 0;
70 return;
71 }
72 memcpy(t, s, n + 1);
73 m_chr = t;
74 m_len = n;
75 }
76
~BaseString()77 BaseString::~BaseString()
78 {
79 delete[] m_chr;
80 }
81
82 BaseString&
assign(const char * s)83 BaseString::assign(const char* s)
84 {
85 if (s == NULL)
86 {
87 m_chr = NULL;
88 m_len = 0;
89 return *this;
90 }
91 size_t n = strlen(s);
92 char* t = new char[n + 1];
93 if (t)
94 {
95 memcpy(t, s, n + 1);
96 }
97 else
98 {
99 errno = ENOMEM;
100 n = 0;
101 }
102 delete[] m_chr;
103 m_chr = t;
104 m_len = n;
105 return *this;
106 }
107
108 BaseString&
assign(const char * s,size_t n)109 BaseString::assign(const char* s, size_t n)
110 {
111 char* t = new char[n + 1];
112 if (t)
113 {
114 memcpy(t, s, n);
115 t[n] = 0;
116 }
117 else
118 {
119 errno = ENOMEM;
120 n = 0;
121 }
122 delete[] m_chr;
123 m_chr = t;
124 m_len = n;
125 return *this;
126 }
127
128 BaseString&
assign(const BaseString & str,size_t n)129 BaseString::assign(const BaseString& str, size_t n)
130 {
131 if (n > str.m_len)
132 n = str.m_len;
133 return assign(str.m_chr, n);
134 }
135
136 BaseString&
append(const char * s)137 BaseString::append(const char* s)
138 {
139 size_t n = strlen(s);
140 char* t = new char[m_len + n + 1];
141 if (t)
142 {
143 memcpy(t, m_chr, m_len);
144 memcpy(t + m_len, s, n + 1);
145 }
146 else
147 {
148 errno = ENOMEM;
149 m_len = 0;
150 n = 0;
151 }
152 delete[] m_chr;
153 m_chr = t;
154 m_len += n;
155 return *this;
156 }
157
158 BaseString&
append(char c)159 BaseString::append(char c) {
160 return appfmt("%c", c);
161 }
162
163 BaseString&
append(const BaseString & str)164 BaseString::append(const BaseString& str)
165 {
166 return append(str.m_chr);
167 }
168
169 BaseString&
append(const Vector<BaseString> & vector,const BaseString & separator)170 BaseString::append(const Vector<BaseString> &vector,
171 const BaseString &separator) {
172 for(size_t i=0;i<vector.size(); i++) {
173 append(vector[i]);
174 if(i<vector.size()-1)
175 append(separator);
176 }
177 return *this;
178 }
179
180 BaseString&
assfmt(const char * fmt,...)181 BaseString::assfmt(const char *fmt, ...)
182 {
183 char buf[1];
184 va_list ap;
185 int l;
186
187 /* Figure out how long the formatted string will be. A small temporary
188 * buffer is used, because I don't trust all implementations to work
189 * when called as vsnprintf(NULL, 0, ...).
190 */
191 va_start(ap, fmt);
192 l = basestring_vsnprintf(buf, sizeof(buf), fmt, ap) + 1;
193 va_end(ap);
194 if(l > (int)m_len) {
195 char *t = new char[l];
196 if (t == NULL)
197 {
198 errno = ENOMEM;
199 return *this;
200 }
201 delete[] m_chr;
202 m_chr = t;
203 }
204 va_start(ap, fmt);
205 basestring_vsnprintf(m_chr, l, fmt, ap);
206 va_end(ap);
207 m_len = strlen(m_chr);
208 return *this;
209 }
210
211 BaseString&
appfmt(const char * fmt,...)212 BaseString::appfmt(const char *fmt, ...)
213 {
214 char buf[1];
215 va_list ap;
216 int l;
217
218 /* Figure out how long the formatted string will be. A small temporary
219 * buffer is used, because I don't trust all implementations to work
220 * when called as vsnprintf(NULL, 0, ...).
221 */
222 va_start(ap, fmt);
223 l = basestring_vsnprintf(buf, sizeof(buf), fmt, ap) + 1;
224 va_end(ap);
225 char *tmp = new char[l];
226 if (tmp == NULL)
227 {
228 errno = ENOMEM;
229 return *this;
230 }
231 va_start(ap, fmt);
232 basestring_vsnprintf(tmp, l, fmt, ap);
233 va_end(ap);
234 append(tmp);
235 delete[] tmp;
236 return *this;
237 }
238
239 BaseString&
operator =(const BaseString & str)240 BaseString::operator=(const BaseString& str)
241 {
242 if (this != &str) {
243 this->assign(str);
244 }
245 return *this;
246 }
247
248 int
split(Vector<BaseString> & v,const BaseString & separator,int maxSize) const249 BaseString::split(Vector<BaseString> &v,
250 const BaseString &separator,
251 int maxSize) const {
252 char *str = strdup(m_chr);
253 int i, start, len, num = 0;
254 len = strlen(str);
255 for(start = i = 0;
256 (i <= len) && ( (maxSize<0) || ((int)v.size()<=maxSize-1) );
257 i++) {
258 if(strchr(separator.c_str(), str[i]) || i == len) {
259 if(maxSize < 0 || (int)v.size() < maxSize-1)
260 str[i] = '\0';
261 v.push_back(BaseString(str+start));
262 num++;
263 start = i+1;
264 }
265 }
266 free(str);
267
268 return num;
269 }
270
271 ssize_t
indexOf(char c)272 BaseString::indexOf(char c) {
273 char *p;
274 p = strchr(m_chr, c);
275 if(p == NULL)
276 return -1;
277 return (ssize_t)(p-m_chr);
278 }
279
280 ssize_t
lastIndexOf(char c)281 BaseString::lastIndexOf(char c) {
282 char *p;
283 p = strrchr(m_chr, c);
284 if(p == NULL)
285 return -1;
286 return (ssize_t)(p-m_chr);
287 }
288
289 BaseString
substr(ssize_t start,ssize_t stop)290 BaseString::substr(ssize_t start, ssize_t stop) {
291 if(stop < 0)
292 stop = length();
293 ssize_t len = stop-start;
294 if(len <= 0)
295 return BaseString("");
296 BaseString s;
297 s.assign(m_chr+start, len);
298 return s;
299 }
300
301 static bool
iswhite(char c)302 iswhite(char c) {
303 switch(c) {
304 case ' ':
305 case '\t':
306 return true;
307 default:
308 return false;
309 }
310 /* NOTREACHED */
311 }
312
313 char **
argify(const char * argv0,const char * src)314 BaseString::argify(const char *argv0, const char *src) {
315 Vector<char *> vargv;
316
317 if(argv0 != NULL)
318 {
319 char *t = strdup(argv0);
320 if (t == NULL)
321 {
322 errno = ENOMEM;
323 return NULL;
324 }
325 if (vargv.push_back(t))
326 {
327 free(t);
328 return NULL;
329 }
330 }
331
332 char *tmp = new char[strlen(src)+1];
333 if (tmp == NULL)
334 {
335 for(size_t i = 0; i < vargv.size(); i++)
336 free(vargv[i]);
337 errno = ENOMEM;
338 return NULL;
339 }
340 char *dst = tmp;
341 const char *end = src + strlen(src);
342 /* Copy characters from src to destination, while compacting them
343 * so that all whitespace is compacted and replaced by a NUL-byte.
344 * At the same time, add pointers to strings in the vargv vector.
345 * When whitespace is detected, the characters '"' and '\' are honored,
346 * to make it possible to give arguments containing whitespace.
347 * The semantics of '"' and '\' match that of most Unix shells.
348 */
349 while(src < end && *src) {
350 /* Skip initial whitespace */
351 while(src < end && *src && iswhite(*src))
352 src++;
353
354 char *begin = dst;
355 while(src < end && *src) {
356 /* Handle '"' quotation */
357 if(*src == '"') {
358 src++;
359 while(src < end && *src && *src != '"') {
360 if(*src == '\\')
361 src++;
362 *dst++ = *src++;
363 }
364 src++;
365 if(src >= end)
366 goto end;
367 }
368
369 /* Handle '\' */
370 if(*src == '\\')
371 src++;
372 else if(iswhite(*src))
373 break;
374
375 /* Actually copy characters */
376 *dst++ = *src++;
377 }
378
379 /* Make sure the string is properly terminated */
380 *dst++ = '\0';
381 src++;
382
383 {
384 char *t = strdup(begin);
385 if (t == NULL)
386 {
387 delete[] tmp;
388 for(size_t i = 0; i < vargv.size(); i++)
389 free(vargv[i]);
390 errno = ENOMEM;
391 return NULL;
392 }
393 if (vargv.push_back(t))
394 {
395 free(t);
396 delete[] tmp;
397 for(size_t i = 0; i < vargv.size(); i++)
398 free(vargv[i]);
399 return NULL;
400 }
401 }
402 }
403 end:
404
405 delete[] tmp;
406 if (vargv.push_back(NULL))
407 {
408 for(size_t i = 0; i < vargv.size(); i++)
409 free(vargv[i]);
410 return NULL;
411 }
412
413 /* Convert the C++ Vector into a C-vector of strings, suitable for
414 * calling execv().
415 */
416 char **argv = (char **)malloc(sizeof(*argv) * (vargv.size()));
417 if(argv == NULL)
418 {
419 for(size_t i = 0; i < vargv.size(); i++)
420 free(vargv[i]);
421 errno = ENOMEM;
422 return NULL;
423 }
424
425 for(size_t i = 0; i < vargv.size(); i++){
426 argv[i] = vargv[i];
427 }
428
429 return argv;
430 }
431
432 BaseString&
trim(const char * delim)433 BaseString::trim(const char * delim){
434 trim(m_chr, delim);
435 m_len = strlen(m_chr);
436 return * this;
437 }
438
439 char*
trim(char * str,const char * delim)440 BaseString::trim(char * str, const char * delim){
441 int len = strlen(str) - 1;
442 for(; len > 0 && strchr(delim, str[len]); len--);
443
444 int pos = 0;
445 for(; pos <= len && strchr(delim, str[pos]); pos++);
446
447 if(pos > len){
448 str[0] = 0;
449 return 0;
450 } else {
451 memmove(str, &str[pos], len - pos + 1);
452 str[len-pos+1] = 0;
453 }
454
455 return str;
456 }
457
458 int
vsnprintf(char * str,size_t size,const char * format,va_list ap)459 BaseString::vsnprintf(char *str, size_t size, const char *format, va_list ap)
460 {
461 return(basestring_vsnprintf(str, size, format, ap));
462 }
463
464 int
snprintf(char * str,size_t size,const char * format,...)465 BaseString::snprintf(char *str, size_t size, const char *format, ...)
466 {
467 va_list ap;
468 va_start(ap, format);
469 int ret= basestring_vsnprintf(str, size, format, ap);
470 va_end(ap);
471 return(ret);
472 }
473
474
475 #ifdef TEST_BASE_STRING
476
477 /*
478 g++ -g -Wall -o tbs -DTEST_BASE_STRING -I$NDB_TOP/include/util \
479 -I$NDB_TOP/include/portlib BaseString.cpp
480 valgrind ./tbs
481 */
482
main()483 int main()
484 {
485 BaseString s("abc");
486 BaseString t(s);
487 s.assign("def");
488 t.append("123");
489 assert(s == "def");
490 assert(t == "abc123");
491 s.assign("");
492 t.assign("");
493 for (unsigned i = 0; i < 1000; i++) {
494 s.append("xyz");
495 t.assign(s);
496 assert(strlen(t.c_str()) % 3 == 0);
497 }
498
499 {
500 BaseString s(":123:abc:;:foo:");
501 Vector<BaseString> v;
502 assert(s.split(v, ":;") == 7);
503
504 assert(v[0] == "");
505 assert(v[1] == "123");
506 assert(v[2] == "abc");
507 assert(v[3] == "");
508 assert(v[4] == "");
509 assert(v[5] == "foo");
510 assert(v[6] == "");
511 }
512
513 {
514 BaseString s(":123:abc:foo:bar");
515 Vector<BaseString> v;
516 assert(s.split(v, ":;", 4) == 4);
517
518 assert(v[0] == "");
519 assert(v[1] == "123");
520 assert(v[2] == "abc");
521 assert(v[3] == "foo:bar");
522
523 BaseString n;
524 n.append(v, "()");
525 assert(n == "()123()abc()foo:bar");
526 n = "";
527 n.append(v);
528 assert(n == " 123 abc foo:bar");
529 }
530
531 {
532 assert(BaseString("hamburger").substr(4,2) == "");
533 assert(BaseString("hamburger").substr(3) == "burger");
534 assert(BaseString("hamburger").substr(4,8) == "urge");
535 assert(BaseString("smiles").substr(1,5) == "mile");
536 assert(BaseString("012345").indexOf('2') == 2);
537 assert(BaseString("hej").indexOf('X') == -1);
538 }
539
540 {
541 assert(BaseString(" 1").trim(" ") == "1");
542 assert(BaseString("1 ").trim(" ") == "1");
543 assert(BaseString(" 1 ").trim(" ") == "1");
544 assert(BaseString("abc\t\n\r kalleabc\t\r\n").trim("abc\t\r\n ") == "kalle");
545 assert(BaseString(" ").trim(" ") == "");
546 }
547 return 0;
548 }
549
550 #endif
551
552 template class Vector<char *>;
553 template class Vector<BaseString>;
554