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