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