1 /*
2    Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
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, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 /* -*- c-basic-offset: 4; -*- */
26 #include <ndb_global.h>
27 #include <BaseString.hpp>
28 #include "basestring_vsnprintf.h"
29 
BaseString()30 BaseString::BaseString()
31 {
32     m_chr = new char[1];
33     if (m_chr == NULL)
34     {
35       errno = ENOMEM;
36       m_len = 0;
37       return;
38     }
39     m_chr[0] = 0;
40     m_len = 0;
41 }
42 
BaseString(const char * s)43 BaseString::BaseString(const char* s)
44 {
45     if (s == NULL)
46     {
47       m_chr = NULL;
48       m_len = 0;
49       return;
50     }
51     const size_t n = strlen(s);
52     m_chr = new char[n + 1];
53     if (m_chr == NULL)
54     {
55       errno = ENOMEM;
56       m_len = 0;
57       return;
58     }
59     memcpy(m_chr, s, n + 1);
60     m_len = n;
61 }
62 
BaseString(const char * s,size_t n)63 BaseString::BaseString(const char * s, size_t n)
64 {
65   if (s == NULL || n == 0)
66   {
67     m_chr = NULL;
68     m_len = 0;
69     return;
70   }
71   m_chr = new char[n + 1];
72   if (m_chr == NULL)
73   {
74     errno = ENOMEM;
75     m_len = 0;
76     return;
77   }
78   memcpy(m_chr, s, n);
79   m_chr[n] = 0;
80   m_len = n;
81 }
82 
BaseString(const BaseString & str)83 BaseString::BaseString(const BaseString& str)
84 {
85     const char* const s = str.m_chr;
86     const size_t n = str.m_len;
87     if (s == NULL)
88     {
89       m_chr = NULL;
90       m_len = 0;
91       return;
92     }
93     char* t = new char[n + 1];
94     if (t == NULL)
95     {
96       errno = ENOMEM;
97       m_chr = NULL;
98       m_len = 0;
99       return;
100     }
101     memcpy(t, s, n + 1);
102     m_chr = t;
103     m_len = n;
104 }
105 
~BaseString()106 BaseString::~BaseString()
107 {
108     delete[] m_chr;
109 }
110 
111 BaseString&
assign(const char * s)112 BaseString::assign(const char* s)
113 {
114     if (s == NULL)
115     {
116       if (m_chr)
117         delete[] m_chr;
118       m_chr = NULL;
119       m_len = 0;
120       return *this;
121     }
122     size_t n = strlen(s);
123     char* t = new char[n + 1];
124     if (t)
125     {
126       memcpy(t, s, n + 1);
127     }
128     else
129     {
130       errno = ENOMEM;
131       n = 0;
132     }
133     delete[] m_chr;
134     m_chr = t;
135     m_len = n;
136     return *this;
137 }
138 
139 BaseString&
assign(const char * s,size_t n)140 BaseString::assign(const char* s, size_t n)
141 {
142     char* t = new char[n + 1];
143     if (t)
144     {
145       memcpy(t, s, n);
146       t[n] = 0;
147     }
148     else
149     {
150       errno = ENOMEM;
151       n = 0;
152     }
153     delete[] m_chr;
154     m_chr = t;
155     m_len = n;
156     return *this;
157 }
158 
159 BaseString&
assign(const BaseString & str,size_t n)160 BaseString::assign(const BaseString& str, size_t n)
161 {
162     if (n > str.m_len)
163 	n = str.m_len;
164     return assign(str.m_chr, n);
165 }
166 
167 BaseString&
append(const char * s)168 BaseString::append(const char* s)
169 {
170     if (s == NULL)
171       return *this;
172 
173     size_t n = strlen(s);
174     char* t = new char[m_len + n + 1];
175     if (t)
176     {
177       memcpy(t, m_chr, m_len);
178       memcpy(t + m_len, s, n + 1);
179     }
180     else
181     {
182       errno = ENOMEM;
183       m_len = 0;
184       n = 0;
185     }
186     delete[] m_chr;
187     m_chr = t;
188     m_len += n;
189     return *this;
190 }
191 
192 BaseString&
append(char c)193 BaseString::append(char c) {
194     return appfmt("%c", c);
195 }
196 
197 BaseString&
append(const BaseString & str)198 BaseString::append(const BaseString& str)
199 {
200     return append(str.m_chr);
201 }
202 
203 BaseString&
append(const Vector<BaseString> & vector,const BaseString & separator)204 BaseString::append(const Vector<BaseString> &vector,
205 		   const BaseString &separator) {
206     for(size_t i=0;i<vector.size(); i++) {
207 	append(vector[i]);
208 	if(i<vector.size()-1)
209 	    append(separator);
210     }
211     return *this;
212 }
213 
214 BaseString&
assfmt(const char * fmt,...)215 BaseString::assfmt(const char *fmt, ...)
216 {
217     char buf[1];
218     va_list ap;
219     int l;
220 
221     /* Figure out how long the formatted string will be. A small temporary
222      * buffer is used, because I don't trust all implementations to work
223      * when called as vsnprintf(NULL, 0, ...).
224      */
225     va_start(ap, fmt);
226     l = basestring_vsnprintf(buf, sizeof(buf), fmt, ap) + 1;
227     va_end(ap);
228     if(l > (int)m_len) {
229         char *t = new char[l];
230         if (t == NULL)
231         {
232           errno = ENOMEM;
233           return *this;
234         }
235 	delete[] m_chr;
236 	m_chr = t;
237     }
238     va_start(ap, fmt);
239     l = basestring_vsnprintf(m_chr, l, fmt, ap);
240     assert(l == (int)strlen(m_chr));
241     va_end(ap);
242     m_len = strlen(m_chr);
243     return *this;
244 }
245 
246 BaseString&
appfmt(const char * fmt,...)247 BaseString::appfmt(const char *fmt, ...)
248 {
249     char buf[1];
250     va_list ap;
251     int l;
252 
253     /* Figure out how long the formatted string will be. A small temporary
254      * buffer is used, because I don't trust all implementations to work
255      * when called as vsnprintf(NULL, 0, ...).
256      */
257     va_start(ap, fmt);
258     l = basestring_vsnprintf(buf, sizeof(buf), fmt, ap) + 1;
259     va_end(ap);
260     char *tmp = new char[l];
261     if (tmp == NULL)
262     {
263       errno = ENOMEM;
264       return *this;
265     }
266     va_start(ap, fmt);
267     basestring_vsnprintf(tmp, l, fmt, ap);
268     va_end(ap);
269     append(tmp);
270     delete[] tmp;
271     return *this;
272 }
273 
274 BaseString&
operator =(const BaseString & str)275 BaseString::operator=(const BaseString& str)
276 {
277     if (this != &str) {
278 	this->assign(str);
279     }
280     return *this;
281 }
282 
283 int
split(Vector<BaseString> & v,const BaseString & separator,int maxSize) const284 BaseString::split(Vector<BaseString> &v,
285 		  const BaseString &separator,
286 		  int maxSize) const {
287     char *str = strdup(m_chr);
288     int i, start, len, num = 0;
289     len = strlen(str);
290     for(start = i = 0;
291 	(i <= len) && ( (maxSize<0) || ((int)v.size()<=maxSize-1) );
292 	i++) {
293 	if(strchr(separator.c_str(), str[i]) || i == len) {
294 	    if(maxSize < 0 || (int)v.size() < maxSize-1)
295 		str[i] = '\0';
296 	    v.push_back(BaseString(str+start));
297 	    num++;
298 	    start = i+1;
299 	}
300     }
301     free(str);
302 
303     return num;
304 }
305 
306 ssize_t
indexOf(char c) const307 BaseString::indexOf(char c) const {
308     char *p;
309     p = strchr(m_chr, c);
310     if(p == NULL)
311 	return -1;
312     return (ssize_t)(p-m_chr);
313 }
314 
315 ssize_t
lastIndexOf(char c) const316 BaseString::lastIndexOf(char c) const {
317     char *p;
318     p = strrchr(m_chr, c);
319     if(p == NULL)
320 	return -1;
321     return (ssize_t)(p-m_chr);
322 }
323 
324 BaseString
substr(ssize_t start,ssize_t stop) const325 BaseString::substr(ssize_t start, ssize_t stop) const {
326     if(stop < 0)
327 	stop = length();
328     ssize_t len = stop-start;
329     if(len <= 0)
330 	return BaseString("");
331     BaseString s;
332     s.assign(m_chr+start, len);
333     return s;
334 }
335 
336 static bool
iswhite(char c)337 iswhite(char c) {
338   switch(c) {
339   case ' ':
340   case '\t':
341     return true;
342   default:
343     return false;
344   }
345   /* NOTREACHED */
346 }
347 
348 char **
argify(const char * argv0,const char * src)349 BaseString::argify(const char *argv0, const char *src) {
350     Vector<char *> vargv;
351 
352     if(argv0 != NULL)
353     {
354       char *t = strdup(argv0);
355       if (t == NULL)
356       {
357         errno = ENOMEM;
358         return NULL;
359       }
360       if (vargv.push_back(t))
361       {
362         free(t);
363         return NULL;
364       }
365     }
366 
367     char *tmp = new char[strlen(src)+1];
368     if (tmp == NULL)
369     {
370       for(size_t i = 0; i < vargv.size(); i++)
371         free(vargv[i]);
372       errno = ENOMEM;
373       return NULL;
374     }
375     char *dst = tmp;
376     const char *end = src + strlen(src);
377     /* Copy characters from src to destination, while compacting them
378      * so that all whitespace is compacted and replaced by a NUL-byte.
379      * At the same time, add pointers to strings in the vargv vector.
380      * When whitespace is detected, the characters '"' and '\' are honored,
381      * to make it possible to give arguments containing whitespace.
382      * The semantics of '"' and '\' match that of most Unix shells.
383      */
384     while(src < end && *src) {
385 	/* Skip initial whitespace */
386 	while(src < end && *src && iswhite(*src))
387 	    src++;
388 
389 	char *begin = dst;
390 	while(src < end && *src) {
391 	    /* Handle '"' quotation */
392 	    if(*src == '"') {
393 		src++;
394 		while(src < end && *src && *src != '"') {
395 		    if(*src == '\\')
396 			src++;
397 		    *dst++ = *src++;
398 		}
399 		src++;
400 		if(src >= end)
401 		    goto end;
402 	    }
403 
404 	    /* Handle '\' */
405 	    if(*src == '\\')
406 		src++;
407 	    else if(iswhite(*src))
408 		break;
409 
410 	    /* Actually copy characters */
411 	    *dst++ = *src++;
412 	}
413 
414 	/* Make sure the string is properly terminated */
415 	*dst++ = '\0';
416 	src++;
417 
418         {
419           char *t = strdup(begin);
420           if (t == NULL)
421           {
422             delete[] tmp;
423             for(size_t i = 0; i < vargv.size(); i++)
424               free(vargv[i]);
425             errno = ENOMEM;
426             return NULL;
427           }
428           if (vargv.push_back(t))
429           {
430             free(t);
431             delete[] tmp;
432             for(size_t i = 0; i < vargv.size(); i++)
433               free(vargv[i]);
434             return NULL;
435           }
436         }
437     }
438  end:
439 
440     delete[] tmp;
441     if (vargv.push_back(NULL))
442     {
443       for(size_t i = 0; i < vargv.size(); i++)
444         free(vargv[i]);
445       return NULL;
446     }
447 
448     /* Convert the C++ Vector into a C-vector of strings, suitable for
449      * calling execv().
450      */
451     char **argv = (char **)malloc(sizeof(*argv) * (vargv.size()));
452     if(argv == NULL)
453     {
454         for(size_t i = 0; i < vargv.size(); i++)
455           free(vargv[i]);
456         errno = ENOMEM;
457 	return NULL;
458     }
459 
460     for(size_t i = 0; i < vargv.size(); i++){
461 	argv[i] = vargv[i];
462     }
463 
464     return argv;
465 }
466 
467 BaseString&
trim(const char * delim)468 BaseString::trim(const char * delim){
469     trim(m_chr, delim);
470     m_len = strlen(m_chr);
471     return * this;
472 }
473 
474 char*
trim(char * str,const char * delim)475 BaseString::trim(char * str, const char * delim){
476     int len = strlen(str) - 1;
477     for(; len > 0 && strchr(delim, str[len]); len--)
478       ;
479 
480     int pos = 0;
481     for(; pos <= len && strchr(delim, str[pos]); pos++)
482       ;
483 
484     if(pos > len){
485 	str[0] = 0;
486 	return 0;
487     } else {
488 	memmove(str, &str[pos], len - pos + 1);
489 	str[len-pos+1] = 0;
490     }
491 
492     return str;
493 }
494 
495 int
vsnprintf(char * str,size_t size,const char * format,va_list ap)496 BaseString::vsnprintf(char *str, size_t size, const char *format, va_list ap)
497 {
498   return(basestring_vsnprintf(str, size, format, ap));
499 }
500 
501 int
snprintf(char * str,size_t size,const char * format,...)502 BaseString::snprintf(char *str, size_t size, const char *format, ...)
503 {
504   va_list ap;
505   va_start(ap, format);
506   int ret= basestring_vsnprintf(str, size, format, ap);
507   va_end(ap);
508   return(ret);
509 }
510 
511 BaseString
getText(unsigned size,const Uint32 data[])512 BaseString::getText(unsigned size, const Uint32 data[])
513 {
514   BaseString to;
515   char * buf = (char*)malloc(32*size+1);
516   if (buf)
517   {
518     BitmaskImpl::getText(size, data, buf);
519     to.append(buf);
520     free(buf);
521   }
522   return to;
523 }
524 
525 BaseString
getPrettyText(unsigned size,const Uint32 data[])526 BaseString::getPrettyText(unsigned size, const Uint32 data[])
527 {
528   const char* delimiter = "";
529   unsigned found = 0;
530   const unsigned MAX_BITS = sizeof(Uint32) * 8 * size;
531   BaseString to;
532   for (unsigned i = 0; i < MAX_BITS; i++)
533   {
534     if (BitmaskImpl::get(size, data, i))
535     {
536       to.appfmt("%s%d", delimiter, i);
537       found++;
538       if (found < BitmaskImpl::count(size, data) - 1)
539         delimiter = ", ";
540       else
541         delimiter = " and ";
542     }
543   }
544   return to;
545 }
546 
547 BaseString
getPrettyTextShort(unsigned size,const Uint32 data[])548 BaseString::getPrettyTextShort(unsigned size, const Uint32 data[])
549 {
550   const char* delimiter = "";
551   const unsigned MAX_BITS = sizeof(Uint32) * 8 * size;
552   BaseString to;
553   for (unsigned i = 0; i < MAX_BITS; i++)
554   {
555     if (BitmaskImpl::get(size, data, i))
556     {
557       to.appfmt("%s%d", delimiter, i);
558       delimiter = ",";
559     }
560   }
561   return to;
562 }
563 
564 const void*
BaseString_get_key(const void * key,size_t * key_length)565 BaseString_get_key(const void* key, size_t* key_length)
566 {
567   const BaseString* str = (const BaseString*)key;
568   *key_length = str->length();
569   return str->c_str();
570 }
571 
572 #ifdef TEST_BASE_STRING
573 
574 #include <NdbTap.hpp>
575 
TAPTEST(BaseString)576 TAPTEST(BaseString)
577 {
578     BaseString s("abc");
579     BaseString t(s);
580     s.assign("def");
581     t.append("123");
582     OK(s == "def");
583     OK(t == "abc123");
584     s.assign("");
585     t.assign("");
586     for (unsigned i = 0; i < 1000; i++) {
587 	s.append("xyz");
588 	t.assign(s);
589 	OK(strlen(t.c_str()) % 3 == 0);
590     }
591 
592     {
593 	BaseString s(":123:abc:;:foo:");
594 	Vector<BaseString> v;
595 	OK(s.split(v, ":;") == 7);
596 
597 	OK(v[0] == "");
598 	OK(v[1] == "123");
599 	OK(v[2] == "abc");
600 	OK(v[3] == "");
601 	OK(v[4] == "");
602 	OK(v[5] == "foo");
603 	OK(v[6] == "");
604     }
605 
606     {
607 	BaseString s(":123:abc:foo:bar");
608 	Vector<BaseString> v;
609 	OK(s.split(v, ":;", 4) == 4);
610 
611 	OK(v[0] == "");
612 	OK(v[1] == "123");
613 	OK(v[2] == "abc");
614 	OK(v[3] == "foo:bar");
615 
616 	BaseString n;
617 	n.append(v, "()");
618 	OK(n == "()123()abc()foo:bar");
619 	n = "";
620 	n.append(v);
621 	OK(n == " 123 abc foo:bar");
622     }
623 
624     {
625 	OK(BaseString("hamburger").substr(4,2) == "");
626 	OK(BaseString("hamburger").substr(3) == "burger");
627 	OK(BaseString("hamburger").substr(4,8) == "urge");
628 	OK(BaseString("smiles").substr(1,5) == "mile");
629 	OK(BaseString("012345").indexOf('2') == 2);
630 	OK(BaseString("hej").indexOf('X') == -1);
631     }
632 
633     {
634 	OK(BaseString(" 1").trim(" ") == "1");
635 	OK(BaseString("1 ").trim(" ") == "1");
636 	OK(BaseString(" 1 ").trim(" ") == "1");
637 	OK(BaseString("abc\t\n\r kalleabc\t\r\n").trim("abc\t\r\n ") == "kalle");
638 	OK(BaseString(" ").trim(" ") == "");
639     }
640 
641     // Tests for BUG#38662
642     BaseString s2(NULL);
643     BaseString s3;
644     BaseString s4("elf");
645 
646     OK(s3.append((const char*)NULL) == "");
647     OK(s4.append((const char*)NULL) == "elf");
648     OK(s4.append(s3) == "elf");
649     OK(s4.append(s2) == "elf");
650     OK(s4.append(s4) == "elfelf");
651 
652     OK(s3.assign((const char*)NULL).c_str() == NULL);
653     OK(s4.assign((const char*)NULL).c_str() == NULL);
654     OK(s4.assign(s4).c_str() == NULL);
655 
656     //tests for Bug #45733 Cluster with more than 4 storage node
657     for(int i=0;i<20;i++)
658     {
659 #define BIG_ASSFMT_OK(X) do{u_int x=(X);OK(s2.assfmt("%*s",x,"Z").length() == x);}while(0)
660       BIG_ASSFMT_OK(8);
661       BIG_ASSFMT_OK(511);
662       BIG_ASSFMT_OK(512);
663       BIG_ASSFMT_OK(513);
664       BIG_ASSFMT_OK(1023);
665       BIG_ASSFMT_OK(1024);
666       BIG_ASSFMT_OK(1025);
667       BIG_ASSFMT_OK(20*1024*1024);
668     }
669 
670     return 1; // OK
671 }
672 
673 #endif
674 
675 template class Vector<BaseString>;
676