1 /*
2    Copyright (c) 2003, 2021, Oracle and/or its affiliates.
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 = (unsigned)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 = (unsigned)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 = (unsigned)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 = (unsigned)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 = (unsigned)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 += (unsigned)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(unsigned 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 = (unsigned)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 = (int)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,size_t pos) const307 BaseString::indexOf(char c, size_t pos) const {
308 
309   if (pos >= m_len)
310     return -1;
311 
312     char *p = strchr(m_chr + pos, c);
313     if(p == NULL)
314 	return -1;
315     return (ssize_t)(p-m_chr);
316 }
317 
318 ssize_t
indexOf(const char * needle,size_t pos) const319 BaseString::indexOf(const char * needle, size_t pos) const {
320 
321   if (pos >= m_len)
322     return -1;
323 
324     char *p = strstr(m_chr + pos, needle);
325     if(p == NULL)
326 	return -1;
327     return (ssize_t)(p-m_chr);
328 }
329 
330 ssize_t
lastIndexOf(char c) const331 BaseString::lastIndexOf(char c) const {
332     char *p;
333     p = strrchr(m_chr, c);
334     if(p == NULL)
335 	return -1;
336     return (ssize_t)(p-m_chr);
337 }
338 
339 BaseString
substr(ssize_t start,ssize_t stop) const340 BaseString::substr(ssize_t start, ssize_t stop) const {
341     if(stop < 0)
342 	stop = length();
343     ssize_t len = stop-start;
344     if(len <= 0)
345 	return BaseString("");
346     BaseString s;
347     s.assign(m_chr+start, len);
348     return s;
349 }
350 
351 static bool
iswhite(char c)352 iswhite(char c) {
353   switch(c) {
354   case ' ':
355   case '\t':
356     return true;
357   default:
358     return false;
359   }
360   /* NOTREACHED */
361 }
362 
363 char **
argify(const char * argv0,const char * src)364 BaseString::argify(const char *argv0, const char *src) {
365     Vector<char *> vargv;
366 
367     if(argv0 != NULL)
368     {
369       char *t = strdup(argv0);
370       if (t == NULL)
371       {
372         errno = ENOMEM;
373         return NULL;
374       }
375       if (vargv.push_back(t))
376       {
377         free(t);
378         return NULL;
379       }
380     }
381 
382     char *tmp = new char[strlen(src)+1];
383     if (tmp == NULL)
384     {
385       for(unsigned i = 0; i < vargv.size(); i++)
386         free(vargv[i]);
387       errno = ENOMEM;
388       return NULL;
389     }
390     char *dst = tmp;
391     const char *end = src + strlen(src);
392     /* Copy characters from src to destination, while compacting them
393      * so that all whitespace is compacted and replaced by a NUL-byte.
394      * At the same time, add pointers to strings in the vargv vector.
395      * When whitespace is detected, the characters '"' and '\' are honored,
396      * to make it possible to give arguments containing whitespace.
397      * The semantics of '"' and '\' match that of most Unix shells.
398      */
399     while(src < end && *src) {
400 	/* Skip initial whitespace */
401 	while(src < end && *src && iswhite(*src))
402 	    src++;
403 
404 	char *begin = dst;
405 	while(src < end && *src) {
406 	    /* Handle '"' quotation */
407 	    if(*src == '"') {
408 		src++;
409 		while(src < end && *src && *src != '"') {
410 		    if(*src == '\\')
411 			src++;
412 		    *dst++ = *src++;
413 		}
414 		src++;
415 		if(src >= end)
416 		    goto end;
417 	    }
418 
419 	    /* Handle '\' */
420 	    if(*src == '\\')
421 		src++;
422 	    else if(iswhite(*src))
423 		break;
424 
425 	    /* Actually copy characters */
426 	    *dst++ = *src++;
427 	}
428 
429 	/* Make sure the string is properly terminated */
430 	*dst++ = '\0';
431 	src++;
432 
433         {
434           char *t = strdup(begin);
435           if (t == NULL)
436           {
437             delete[] tmp;
438             for(unsigned i = 0; i < vargv.size(); i++)
439               free(vargv[i]);
440             errno = ENOMEM;
441             return NULL;
442           }
443           if (vargv.push_back(t))
444           {
445             free(t);
446             delete[] tmp;
447             for(unsigned i = 0; i < vargv.size(); i++)
448               free(vargv[i]);
449             return NULL;
450           }
451         }
452     }
453  end:
454 
455     delete[] tmp;
456     if (vargv.push_back(NULL))
457     {
458       for(unsigned i = 0; i < vargv.size(); i++)
459         free(vargv[i]);
460       return NULL;
461     }
462 
463     /* Convert the C++ Vector into a C-vector of strings, suitable for
464      * calling execv().
465      */
466     char **argv = (char **)malloc(sizeof(*argv) * (vargv.size()));
467     if(argv == NULL)
468     {
469         for(unsigned i = 0; i < vargv.size(); i++)
470           free(vargv[i]);
471         errno = ENOMEM;
472 	return NULL;
473     }
474 
475     for(unsigned i = 0; i < vargv.size(); i++){
476 	argv[i] = vargv[i];
477     }
478 
479     return argv;
480 }
481 
482 BaseString&
trim(const char * delim)483 BaseString::trim(const char * delim){
484     trim(m_chr, delim);
485     m_len = (unsigned)strlen(m_chr);
486     return * this;
487 }
488 
489 char*
trim(char * str,const char * delim)490 BaseString::trim(char * str, const char * delim){
491     int len = (int)strlen(str) - 1;
492     for(; len > 0 && strchr(delim, str[len]); len--)
493       ;
494 
495     int pos = 0;
496     for(; pos <= len && strchr(delim, str[pos]); pos++)
497       ;
498 
499     if(pos > len){
500 	str[0] = 0;
501 	return 0;
502     } else {
503 	memmove(str, &str[pos], len - pos + 1);
504 	str[len-pos+1] = 0;
505     }
506 
507     return str;
508 }
509 
510 int
vsnprintf(char * str,size_t size,const char * format,va_list ap)511 BaseString::vsnprintf(char *str, size_t size, const char *format, va_list ap)
512 {
513   return(basestring_vsnprintf(str, size, format, ap));
514 }
515 
516 int
snprintf(char * str,size_t size,const char * format,...)517 BaseString::snprintf(char *str, size_t size, const char *format, ...)
518 {
519   va_list ap;
520   va_start(ap, format);
521   int ret= basestring_vsnprintf(str, size, format, ap);
522   va_end(ap);
523   return(ret);
524 }
525 
526 BaseString
getText(unsigned size,const Uint32 data[])527 BaseString::getText(unsigned size, const Uint32 data[])
528 {
529   BaseString to;
530   char * buf = (char*)malloc(32*size+1);
531   if (buf)
532   {
533     BitmaskImpl::getText(size, data, buf);
534     to.append(buf);
535     free(buf);
536   }
537   return to;
538 }
539 
540 BaseString
getPrettyText(unsigned size,const Uint32 data[])541 BaseString::getPrettyText(unsigned size, const Uint32 data[])
542 {
543   const char* delimiter = "";
544   unsigned found = 0;
545   const unsigned MAX_BITS = sizeof(Uint32) * 8 * size;
546   BaseString to;
547   for (unsigned i = 0; i < MAX_BITS; i++)
548   {
549     if (BitmaskImpl::get(size, data, i))
550     {
551       to.appfmt("%s%d", delimiter, i);
552       found++;
553       if (found < BitmaskImpl::count(size, data) - 1)
554         delimiter = ", ";
555       else
556         delimiter = " and ";
557     }
558   }
559   return to;
560 }
561 
562 BaseString
getPrettyTextShort(unsigned size,const Uint32 data[])563 BaseString::getPrettyTextShort(unsigned size, const Uint32 data[])
564 {
565   const char* delimiter = "";
566   const unsigned MAX_BITS = sizeof(Uint32) * 8 * size;
567   BaseString to;
568   for (unsigned i = 0; i < MAX_BITS; i++)
569   {
570     if (BitmaskImpl::get(size, data, i))
571     {
572       to.appfmt("%s%d", delimiter, i);
573       delimiter = ",";
574     }
575   }
576   return to;
577 }
578 
579 const void*
BaseString_get_key(const void * key,size_t * key_length)580 BaseString_get_key(const void* key, size_t* key_length)
581 {
582   const BaseString* str = (const BaseString*)key;
583   *key_length = str->length();
584   return str->c_str();
585 }
586 
587 size_t
hexdump(char * buf,size_t len,const Uint32 * wordbuf,size_t numwords)588 BaseString::hexdump(char * buf, size_t len, const Uint32 * wordbuf, size_t numwords)
589 {
590   /**
591    * If not all words are printed end with "...\n".
592    * Words are written as "H'11223344 ", 11 character each.
593    */
594   size_t offset = 0;
595   size_t words_to_dump = numwords;
596   const size_t max_words_to_dump = (len - 5) / 11;
597   if (words_to_dump > max_words_to_dump)
598   {
599     words_to_dump = max_words_to_dump;
600   }
601   for (size_t i = 0 ; i < words_to_dump ; i ++ )
602   {
603     // Write at most 6 words per line
604     char sep = (i % 6 == 5) ? '\n' : ' ';
605     assert(offset + 11 < len);
606     int n = BaseString::snprintf(buf + offset, len - offset, "H'%08x%c", wordbuf[i], sep);
607     assert(n == 11);
608     offset += n;
609   }
610   if (words_to_dump < numwords)
611   {
612     assert(offset + 4 < len);
613     int n = BaseString::snprintf(buf + offset, len - offset, "...\n");
614     assert(n == 4);
615     offset += n;
616   }
617   else
618   {
619     assert(offset + 1 < len);
620     int n = BaseString::snprintf(buf + offset, len - offset, "\n");
621     assert(n == 1);
622     offset += n;
623   }
624   return offset;
625 }
626 
627 #ifdef TEST_BASE_STRING
628 
629 #include <NdbTap.hpp>
630 
TAPTEST(BaseString)631 TAPTEST(BaseString)
632 {
633     BaseString s("abc");
634     BaseString t(s);
635     s.assign("def");
636     t.append("123");
637     OK(s == "def");
638     OK(t == "abc123");
639     s.assign("");
640     t.assign("");
641     for (unsigned i = 0; i < 1000; i++) {
642 	s.append("xyz");
643 	t.assign(s);
644 	OK(strlen(t.c_str()) % 3 == 0);
645     }
646 
647     {
648 	BaseString s(":123:abc:;:foo:");
649 	Vector<BaseString> v;
650 	OK(s.split(v, ":;") == 7);
651 
652 	OK(v[0] == "");
653 	OK(v[1] == "123");
654 	OK(v[2] == "abc");
655 	OK(v[3] == "");
656 	OK(v[4] == "");
657 	OK(v[5] == "foo");
658 	OK(v[6] == "");
659     }
660 
661     {
662 	BaseString s(":123:abc:foo:bar");
663 	Vector<BaseString> v;
664 	OK(s.split(v, ":;", 4) == 4);
665 
666 	OK(v[0] == "");
667 	OK(v[1] == "123");
668 	OK(v[2] == "abc");
669 	OK(v[3] == "foo:bar");
670 
671 	BaseString n;
672 	n.append(v, "()");
673 	OK(n == "()123()abc()foo:bar");
674 	n = "";
675 	n.append(v);
676 	OK(n == " 123 abc foo:bar");
677     }
678 
679     {
680 	OK(BaseString("hamburger").substr(4,2) == "");
681 	OK(BaseString("hamburger").substr(3) == "burger");
682 	OK(BaseString("hamburger").substr(4,8) == "urge");
683 	OK(BaseString("smiles").substr(1,5) == "mile");
684 	OK(BaseString("012345").indexOf('2') == 2);
685 	OK(BaseString("hej").indexOf('X') == -1);
686     }
687 
688     {
689 	OK(BaseString(" 1").trim(" ") == "1");
690 	OK(BaseString("1 ").trim(" ") == "1");
691 	OK(BaseString(" 1 ").trim(" ") == "1");
692 	OK(BaseString("abc\t\n\r kalleabc\t\r\n").trim("abc\t\r\n ") == "kalle");
693 	OK(BaseString(" ").trim(" ") == "");
694     }
695 
696     // Tests for BUG#38662
697     BaseString s2(NULL);
698     BaseString s3;
699     BaseString s4("elf");
700 
701     OK(s3.append((const char*)NULL) == "");
702     OK(s4.append((const char*)NULL) == "elf");
703     OK(s4.append(s3) == "elf");
704     OK(s4.append(s2) == "elf");
705     OK(s4.append(s4) == "elfelf");
706 
707     OK(s3.assign((const char*)NULL).c_str() == NULL);
708     OK(s4.assign((const char*)NULL).c_str() == NULL);
709     OK(s4.assign(s4).c_str() == NULL);
710 
711     //tests for Bug #45733 Cluster with more than 4 storage node
712     for(int i=0;i<20;i++)
713     {
714 #define BIG_ASSFMT_OK(X) do{u_int x=(X);OK(s2.assfmt("%*s",x,"Z").length() == x);}while(0)
715       BIG_ASSFMT_OK(8);
716       BIG_ASSFMT_OK(511);
717       BIG_ASSFMT_OK(512);
718       BIG_ASSFMT_OK(513);
719       BIG_ASSFMT_OK(1023);
720       BIG_ASSFMT_OK(1024);
721       BIG_ASSFMT_OK(1025);
722       BIG_ASSFMT_OK(20*1024*1024);
723     }
724 
725     return 1; // OK
726 }
727 
728 #endif
729 
730 template class Vector<BaseString>;
731