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