1 /**
2  * String.cpp
3  * This file is part of the YATE Project http://YATE.null.ro
4  *
5  * Yet Another Telephony Engine - a fully featured software PBX and IVR
6  * Copyright (C) 2004-2014 Null Team
7  *
8  * This software is distributed under multiple licenses;
9  * see the COPYING file in the main directory for licensing
10  * information for this specific distribution.
11  *
12  * This use of this software may be subject to additional restrictions.
13  * See the LEGAL file in the main directory for details.
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.
18  */
19 
20 #include "yateclass.h"
21 
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <regex.h>
27 
28 #if (defined(WORDS_BIGENDIAN) || defined(BIGENDIAN))
29 #define ENDIANNESS_NATIVE (UChar::BE)
30 #define ENDIANNESS_OPPOSITE (UChar::LE)
31 #else
32 #define ENDIANNESS_NATIVE (UChar::LE)
33 #define ENDIANNESS_OPPOSITE (UChar::BE)
34 #endif
35 
36 
37 namespace TelEngine {
38 
39 // String to regular integer conversion, takes into account overflows
strtoi(const char * nptr,char ** endptr,int base)40 static int strtoi(const char* nptr, char** endptr, int base)
41 {
42     errno = 0;
43     long int val = ::strtol(nptr,endptr,base);
44 #if INT_MAX != LONG_MAX
45     if (val >= INT_MAX) {
46 	errno = ERANGE;
47 	val = INT_MAX;
48     }
49     else if (val <= INT_MIN) {
50 	errno = ERANGE;
51 	val = INT_MIN;
52     }
53 #endif
54     // on overflow/underflow mark the entire string as unreadable
55     if ((errno == ERANGE) && endptr)
56 	*endptr = (char*) nptr;
57     return (int) val;
58 }
59 
operator +(const String & s1,const String & s2)60 String operator+(const String& s1, const String& s2)
61 {
62     String s(s1.c_str());
63     s += s2.c_str();
64     return s;
65 }
66 
operator +(const String & s1,const char * s2)67 String operator+(const String& s1, const char* s2)
68 {
69     String s(s1.c_str());
70     s += s2;
71     return s;
72 }
73 
operator +(const char * s1,const String & s2)74 String operator+(const char* s1, const String& s2)
75 {
76     String s(s1);
77     s += s2;
78     return s;
79 }
80 
lookup(const char * str,const TokenDict * tokens,int defvalue,int base)81 int lookup(const char* str, const TokenDict* tokens, int defvalue, int base)
82 {
83     if (!str)
84 	return defvalue;
85     if (tokens) {
86 	for (; tokens->token; tokens++)
87 	    if (!::strcmp(str,tokens->token))
88 		return tokens->value;
89     }
90     char *eptr = 0;
91     int val = strtoi(str,&eptr,base);
92     if (!eptr || *eptr)
93 	return defvalue;
94     return val;
95 }
96 
lookup(int value,const TokenDict * tokens,const char * defvalue)97 const char* lookup(int value, const TokenDict* tokens, const char* defvalue)
98 {
99     if (tokens) {
100 	for (; tokens->token; tokens++)
101 	    if (value == tokens->value)
102 		return tokens->token;
103     }
104     return defvalue;
105 }
106 
lookup(const char * str,const TokenDict64 * tokens,int64_t defvalue,int base)107 int64_t lookup(const char* str, const TokenDict64* tokens, int64_t defvalue, int base)
108 {
109     if (!str)
110 	return defvalue;
111     if (tokens) {
112 	for (; tokens->token; tokens++)
113 	    if (!::strcmp(str,tokens->token))
114 		return tokens->value;
115     }
116     char* eptr = 0;
117     int64_t val = ::strtoll(str,&eptr,base);
118     if (!eptr || *eptr)
119 	return defvalue;
120     return val;
121 }
122 
lookup(int64_t value,const TokenDict64 * tokens,const char * defvalue)123 const char* lookup(int64_t value, const TokenDict64* tokens, const char* defvalue)
124 {
125     if (tokens) {
126 	for (; tokens->token; tokens++)
127 	    if (value == tokens->value)
128 		return tokens->token;
129     }
130     return defvalue;
131 }
132 
133 #define MAX_MATCH 9
134 
135 class StringMatchPrivate
136 {
137 public:
138     StringMatchPrivate();
139     void fixup();
140     void clear();
141     int count;
142     regmatch_t rmatch[MAX_MATCH+1];
143 };
144 
145 };
146 
147 using namespace TelEngine;
148 
isWordBreak(char c,bool nullOk=false)149 static bool isWordBreak(char c, bool nullOk = false)
150 {
151     return (c == ' ' || c == '\t' || c == '\r' || c == '\n' || (nullOk && !c));
152 }
153 
154 // Decode a single nibble, return -1 on error
hexDecode(char c)155 static int hexDecode(char c)
156 {
157     if (('0' <= c) && (c <= '9'))
158 	return c - '0';
159     if (('A' <= c) && (c <= 'F'))
160 	return c - 'A' + 10;
161     if (('a' <= c) && (c <= 'f'))
162 	return c - 'a' + 10;
163     return -1;
164 }
165 
166 // Encode a single nibble
hexEncode(char nib)167 static inline char hexEncode(char nib)
168 {
169     static const char hex[] = "0123456789abcdef";
170     return hex[nib & 0x0f];
171 }
172 
173 
encode()174 void UChar::encode()
175 {
176     if (m_chr < 0x80) {
177 	m_str[0] = (char)m_chr;
178 	m_str[1] = '\0';
179     }
180     else if (m_chr < 0x800) {
181 	m_str[0] = (char)(0xc0 | ((m_chr >>  6) & 0x1f));
182 	m_str[1] = (char)(0x80 | (m_chr & 0x3f));
183 	m_str[2] = '\0';
184     }
185     else if (m_chr < 0xffff) {
186 	m_str[0] = (char)(0xe0 | ((m_chr >> 12) & 0x0f));
187 	m_str[1] = (char)(0x80 | ((m_chr >>  6) & 0x3f));
188 	m_str[2] = (char)(0x80 | (m_chr & 0x3f));
189 	m_str[3] = '\0';
190     }
191     else if (m_chr < 0x1fffff) {
192 	m_str[0] = (char)(0xf0 | ((m_chr >> 18) & 0x07));
193 	m_str[1] = (char)(0x80 | ((m_chr >> 12) & 0x3f));
194 	m_str[2] = (char)(0x80 | ((m_chr >>  6) & 0x3f));
195 	m_str[3] = (char)(0x80 | (m_chr & 0x3f));
196 	m_str[4] = '\0';
197     }
198     else if (m_chr < 0x3ffffff) {
199 	m_str[0] = (char)(0xf8 | ((m_chr >> 24) & 0x03));
200 	m_str[1] = (char)(0x80 | ((m_chr >> 18) & 0x3f));
201 	m_str[2] = (char)(0x80 | ((m_chr >> 12) & 0x3f));
202 	m_str[3] = (char)(0x80 | ((m_chr >>  6) & 0x3f));
203 	m_str[4] = (char)(0x80 | (m_chr & 0x3f));
204 	m_str[5] = '\0';
205     }
206     else if (m_chr < 0x7fffffff) {
207 	m_str[0] = (char)(0xfc | ((m_chr >> 30) & 0x01));
208 	m_str[1] = (char)(0x80 | ((m_chr >> 24) & 0x3f));
209 	m_str[2] = (char)(0x80 | ((m_chr >> 18) & 0x3f));
210 	m_str[3] = (char)(0x80 | ((m_chr >> 12) & 0x3f));
211 	m_str[4] = (char)(0x80 | ((m_chr >>  6) & 0x3f));
212 	m_str[5] = (char)(0x80 | (m_chr & 0x3f));
213 	m_str[6] = '\0';
214     }
215     else
216 	m_str[0] = '\0';
217 }
218 
decode(const char * & str,uint32_t maxChar,bool overlong)219 bool UChar::decode(const char*& str, uint32_t maxChar, bool overlong)
220 {
221     operator=('\0');
222     if (!str)
223 	return false;
224     if (maxChar < 128)
225 	maxChar = 0x10ffff; // RFC 3629 default limit
226 
227     unsigned int more = 0;
228     uint32_t min = 0;
229     uint32_t val = 0;
230 
231     unsigned char c = (unsigned char)*str++;
232     // from 1st byte we find out how many are supposed to follow
233     if (!c)           // don't advance past NUL
234 	--str;
235     else if (c < 0x80) // 1 byte, 0...0x7F, ASCII characters
236 	val = c & 0x7f;
237     else if (c < 0xc0) // invalid as first UFT-8 byte
238 	return false;
239     else if (c < 0xe0) {
240 	// 2 bytes, 0x80...0x7FF
241 	min = 0x80;
242 	val = c & 0x1f;
243 	more = 1;
244     }
245     else if (c < 0xf0) {
246 	// 3 bytes, 0x800...0xFFFF, Basic Multilingual Plane
247 	min = 0x800;
248 	val = c & 0x0f;
249 	more = 2;
250     }
251     else if (c < 0xf8) {
252 	// 4 bytes, 0x10000...0x1FFFFF, RFC 3629 limit (10FFFF)
253 	min = 0x10000;
254 	val = c & 0x07;
255 	more = 3;
256     }
257     else if (c < 0xfc) {
258 	// 5 bytes, 0x200000...0x3FFFFFF
259 	min = 0x200000;
260 	val = c & 0x03;
261 	more = 4;
262     }
263     else if (c < 0xfe) {
264 	// 6 bytes, 0x4000000...0x7FFFFFFF
265 	min = 0x4000000;
266 	val = c & 0x01;
267 	more = 5;
268     }
269     else
270 	return false;
271 
272     while (more--) {
273 	c = (unsigned char)*str;
274 	// all continuation bytes are in range [128..191]
275 	if ((c & 0xc0) != 0x80)
276 	    return false;
277 	val = (val << 6) | (c & 0x3f);
278 	++str;
279     }
280     operator=(val);
281     // got full value, check for overlongs and out of range
282     if (val > maxChar)
283 	return false;
284     if (val < min && !overlong)
285 	return false;
286     return true;
287 }
288 
swap_u16(uint16_t val,UChar::Endianness order)289 static inline uint16_t swap_u16(uint16_t val, UChar::Endianness order)
290 {
291     if (order < UChar::Native && ENDIANNESS_OPPOSITE == order)
292 	val = ((val & 0xff00) >> 8) | ((val & 0x00ff) << 8);
293     return val;
294 }
295 
decode(uint16_t * & buff,unsigned int & len,Endianness order,uint32_t maxChar)296 bool UChar::decode(uint16_t*& buff, unsigned int& len, Endianness order, uint32_t maxChar)
297 {
298     operator=('\0');
299     if (!(buff && len))
300 	return false;
301     if (maxChar < 128)
302 	maxChar = 0x10ffff; // RFC 3629 default limit
303     uint32_t val = swap_u16(*buff,order);
304     buff++;
305     len--;
306     if (val >= 0xD800 && val < 0xDC00 && len) { // High surrogate
307 	uint16_t low = swap_u16(*buff,order);
308 	if (low >= 0xDC00 && low <= 0xDFFF) {
309 	    buff++;
310 	    len--;
311 	    val = (low - 0xDC00) + (val - 0xD800) * 0x400 + 0x10000;
312 	}
313     }
314     operator=(val);
315     if (code() > maxChar)
316 	return false;
317     return true;
318 }
319 
decode(DataBlock & buff,Endianness order,uint32_t maxChar)320 bool UChar::decode(DataBlock& buff, Endianness order, uint32_t maxChar)
321 {
322     operator=('\0');
323     unsigned int len = buff.length();
324     uint16_t* in = (uint16_t*) buff.data();
325     if (!len || (len & 1))
326 	return false;
327     len = len >> 1;
328     if (!decode(in,len,order,maxChar))
329 	return false;
330     buff.cut(-(int)(buff.length() - len * 2));
331     return true;
332 }
333 
encode(uint16_t * & buff,unsigned int & len,Endianness order)334 bool UChar::encode(uint16_t*& buff, unsigned int& len, Endianness order)
335 {
336     if (!(buff && len && code() <= 0x10ffff))
337 	return false;
338     XDebug(DebugAll,"UChar::encode() UTF-16, char=%s (%x), order=%u",c_str(),m_chr,order);
339     if (m_chr >= 0x10000) { // encode to surrogate pairs
340 	if (len < 2)
341 	    return false; // not enough space to encode
342 	*buff = swap_u16(((m_chr - 0x10000) >> 10) + 0xD800,order);
343 	*(buff + 1) = swap_u16(((m_chr - 0x10000) & 0x3ff) + 0xDC00,order);
344 	buff += 2;
345 	len -=2;
346     }
347     else {
348 	*buff = swap_u16(m_chr,order);
349 	buff++;
350 	len--;
351     }
352     return true;
353 }
354 
encode(DataBlock & buff,Endianness order)355 bool UChar::encode(DataBlock& buff, Endianness order)
356 {
357     uint16_t b[2] = {0};
358     uint16_t* out = b;
359     unsigned int len = 2;
360     if (!encode(out,len,order))
361 	return false;
362     buff.append(b,sizeof(uint16_t) * (2 - len));
363     return true;
364 }
365 
decode(String & out,uint16_t * & buff,unsigned int & len,Endianness order,bool checkBOM,uint32_t maxChar)366 bool UChar::decode(String& out, uint16_t*& buff, unsigned int& len, Endianness order, bool checkBOM, uint32_t maxChar)
367 {
368     if (!(buff && len))
369 	return false;
370     XDebug(DebugAll,"UChar::decode() UTF-16, out=%s, buff=%p, len=%u, order=%u, maxChar=%x",
371 	    out.c_str(),buff,len,order,maxChar);
372     if (checkBOM && (*buff == 0xfeff || *buff == 0xfffe)) {
373 	if (*buff == 0xfeff)  // same endianness
374 	    order = ENDIANNESS_NATIVE;
375 	else
376 	    order = ENDIANNESS_OPPOSITE;
377 	buff++;
378 	len--;
379     }
380     while (buff && len) {
381 	UChar c;
382 	if (!c.decode(buff,len,(Endianness)order,maxChar))
383 	    return false;
384 	out << c;
385     }
386     return true;
387 }
388 
encode(DataBlock & out,const char * & str,Endianness order,bool addBOM)389 bool UChar::encode(DataBlock& out, const char*& str, Endianness order, bool addBOM)
390 {
391     XDebug(DebugAll,"UChar::encode() UTF-16, str=%s, order=%u, addBOM=%s",str,order,String::boolText(addBOM));
392     if (TelEngine::null(str))
393 	return false;
394     if (addBOM) {
395 	uint16_t bom = swap_u16(0xfeff,order);
396 	out.append(&bom,2);
397     }
398     UChar c;
399     while (*str && c.decode(str)) {
400 	if (!c.encode(out,order))
401 	    return false;
402     }
403     return true;
404 }
405 
encode(uint16_t * & buff,unsigned int & len,const char * & str,Endianness order,bool addBOM)406 bool UChar::encode(uint16_t*& buff, unsigned int& len, const char*& str, Endianness order, bool addBOM)
407 {
408     if (TelEngine::null(str))
409 	return false;
410     if (!(buff && len))
411 	return false;
412     XDebug(DebugAll,"UChar::encode() UTF-16, buff=%p, len=%u, str=%s, order=%u, addBOM=%s",
413 	  buff,len,str,order,String::boolText(addBOM));
414     if (addBOM) {
415 	uint16_t bom = swap_u16(0xfeff,order);
416 	*buff = bom;
417 	++buff;
418 	len--;
419     }
420     UChar c;
421     while (*str && c.decode(str)) {
422 	if (!c.encode(buff,len,order))
423 	    return false;
424     }
425     return true;
426 }
427 
428 
StringMatchPrivate()429 StringMatchPrivate::StringMatchPrivate()
430 {
431     XDebug(DebugAll,"StringMatchPrivate::StringMatchPrivate() [%p]",this);
432     clear();
433 }
434 
clear()435 void StringMatchPrivate::clear()
436 {
437     count = 0;
438     for (int i = 0; i <= MAX_MATCH; i++) {
439 	rmatch[i].rm_so = -1;
440 	rmatch[i].rm_eo = 0;
441     }
442 }
443 
fixup()444 void StringMatchPrivate::fixup()
445 {
446     count = 0;
447     rmatch[0].rm_so = rmatch[1].rm_so;
448     rmatch[0].rm_eo = 0;
449     int i, c = 0;
450     for (i = 1; i <= MAX_MATCH; i++) {
451 	if (rmatch[i].rm_so != -1) {
452 	    rmatch[0].rm_eo = rmatch[i].rm_eo - rmatch[0].rm_so;
453 	    rmatch[i].rm_eo -= rmatch[i].rm_so;
454 	    c = i;
455 	}
456 	else
457 	    rmatch[i].rm_eo = 0;
458     }
459     // Cope with the regexp stupidity.
460     if (c > 1) {
461 	for (i = 0; i < c; i++)
462 	    rmatch[i] = rmatch[i+1];
463 	rmatch[c].rm_so = -1;
464 	c--;
465     }
466     count = c;
467 }
468 
469 
470 static const String s_empty;
471 static ObjList s_atoms;
472 static Mutex s_mutex(false,"Atom");
473 
empty()474 const String& String::empty()
475 {
476     return s_empty;
477 }
478 
String()479 String::String()
480     : m_string(0), m_length(0), m_hash(YSTRING_INIT_HASH), m_matches(0)
481 {
482     XDebug(DebugAll,"String::String() [%p]",this);
483 }
484 
String(const char * value,int len)485 String::String(const char* value, int len)
486     : m_string(0), m_length(0), m_hash(YSTRING_INIT_HASH), m_matches(0)
487 {
488     XDebug(DebugAll,"String::String(\"%s\",%d) [%p]",value,len,this);
489     assign(value,len);
490 }
491 
String(const String & value)492 String::String(const String& value)
493     : GenObject(),
494       m_string(0), m_length(0), m_hash(YSTRING_INIT_HASH), m_matches(0)
495 {
496     XDebug(DebugAll,"String::String(%p) [%p]",&value,this);
497     if (!value.null()) {
498 	m_string = ::strdup(value.c_str());
499 	if (!m_string)
500 	    Debug("String",DebugFail,"strdup() returned NULL!");
501 	else
502 	    m_length = value.length();
503 	changed();
504     }
505 }
506 
String(char value,unsigned int repeat)507 String::String(char value, unsigned int repeat)
508     : m_string(0), m_length(0), m_hash(YSTRING_INIT_HASH), m_matches(0)
509 {
510     XDebug(DebugAll,"String::String('%c',%d) [%p]",value,repeat,this);
511     if (value && repeat) {
512 	m_string = (char *) ::malloc(repeat+1);
513 	if (m_string) {
514 	    ::memset(m_string,value,repeat);
515 	    m_string[repeat] = 0;
516 	    m_length = repeat;
517 	}
518 	else
519 	    Debug("String",DebugFail,"malloc(%d) returned NULL!",repeat+1);
520 	changed();
521     }
522 }
523 
String(int32_t value)524 String::String(int32_t value)
525     : m_string(0), m_length(0), m_hash(YSTRING_INIT_HASH), m_matches(0)
526 {
527     XDebug(DebugAll,"String::String(%d) [%p]",value,this);
528     char buf[16];
529     ::sprintf(buf,"%d",value);
530     m_string = ::strdup(buf);
531     if (!m_string)
532 	Debug("String",DebugFail,"strdup() returned NULL!");
533     changed();
534 }
535 
String(int64_t value)536 String::String(int64_t value)
537     : m_string(0), m_length(0), m_hash(YSTRING_INIT_HASH), m_matches(0)
538 {
539     XDebug(DebugAll,"String::String(" FMT64 ") [%p]",value,this);
540     char buf[24];
541     ::sprintf(buf,FMT64,value);
542     m_string = ::strdup(buf);
543     if (!m_string)
544 	Debug("String",DebugFail,"strdup() returned NULL!");
545     changed();
546 }
547 
String(uint32_t value)548 String::String(uint32_t value)
549     : m_string(0), m_length(0), m_hash(YSTRING_INIT_HASH), m_matches(0)
550 {
551     XDebug(DebugAll,"String::String(%u) [%p]",value,this);
552     char buf[16];
553     ::sprintf(buf,"%u",value);
554     m_string = ::strdup(buf);
555     if (!m_string)
556 	Debug("String",DebugFail,"strdup() returned NULL!");
557     changed();
558 }
559 
String(uint64_t value)560 String::String(uint64_t value)
561     : m_string(0), m_length(0), m_hash(YSTRING_INIT_HASH), m_matches(0)
562 {
563     XDebug(DebugAll,"String::String(" FMT64U ") [%p]",value,this);
564     char buf[24];
565     ::sprintf(buf,FMT64U,value);
566     m_string = ::strdup(buf);
567     if (!m_string)
568 	Debug("String",DebugFail,"strdup() returned NULL!");
569     changed();
570 }
571 
String(bool value)572 String::String(bool value)
573     : m_string(0), m_length(0), m_hash(YSTRING_INIT_HASH), m_matches(0)
574 {
575     XDebug(DebugAll,"String::String(%u) [%p]",value,this);
576     m_string = ::strdup(boolText(value));
577     if (!m_string)
578 	Debug("String",DebugFail,"strdup() returned NULL!");
579     changed();
580 }
581 
String(double value)582 String::String(double value)
583     : m_string(0), m_length(0), m_hash(YSTRING_INIT_HASH), m_matches(0)
584 {
585     XDebug(DebugAll,"String::String(%g) [%p]",value,this);
586     char buf[80];
587     ::sprintf(buf,"%g",value);
588     m_string = ::strdup(buf);
589     if (!m_string)
590 	Debug("String",DebugFail,"strdup() returned NULL!");
591     changed();
592 }
593 
String(const String * value)594 String::String(const String* value)
595     : m_string(0), m_length(0), m_hash(YSTRING_INIT_HASH), m_matches(0)
596 {
597     XDebug(DebugAll,"String::String(%p) [%p]",&value,this);
598     if (value && !value->null()) {
599 	m_string = ::strdup(value->c_str());
600 	if (!m_string)
601 	    Debug("String",DebugFail,"strdup() returned NULL!");
602 	else
603 	    m_length = value->length();
604 	changed();
605     }
606 }
607 
~String()608 String::~String()
609 {
610     XDebug(DebugAll,"String::~String() [%p] (\"%s\")",this,m_string);
611     if (m_matches) {
612 	StringMatchPrivate *odata = m_matches;
613 	m_matches = 0;
614 	delete odata;
615     }
616     if (m_string) {
617 	char *odata = m_string;
618 	m_length = 0;
619 	m_string = 0;
620 	::free(odata);
621     }
622 }
623 
assign(const char * value,int len)624 String& String::assign(const char* value, int len)
625 {
626     if (len && value && *value) {
627 	if (len < 0)
628 	    len = ::strlen(value);
629 	else {
630 	    int l = 0;
631 	    for (const char* p = value; l < len; l++)
632 		if (!*p++)
633 		    break;
634 	    len = l;
635 	}
636 	if (value != m_string || len != (int)m_length) {
637 	    char* data = (char*) ::malloc(len+1);
638 	    if (data) {
639 		::memcpy(data,value,len);
640 		data[len] = 0;
641 		char* odata = m_string;
642 		m_string = data;
643 		m_length = len;
644 		changed();
645 		if (odata)
646 		    ::free(odata);
647 	    }
648 	    else
649 		Debug("String",DebugFail,"malloc(%d) returned NULL!",len+1);
650 	}
651     }
652     else
653 	clear();
654     return *this;
655 }
656 
assign(char value,unsigned int repeat)657 String& String::assign(char value, unsigned int repeat)
658 {
659     if (repeat && value) {
660 	char* data = (char*) ::malloc(repeat+1);
661 	if (data) {
662 	    ::memset(data,value,repeat);
663 	    data[repeat] = 0;
664 	    char* odata = m_string;
665 	    m_string = data;
666 	    m_length = repeat;
667 	    changed();
668 	    if (odata)
669 		::free(odata);
670 	}
671 	else
672 	    Debug("String",DebugFail,"malloc(%d) returned NULL!",repeat+1);
673     }
674     else
675 	clear();
676     return *this;
677 }
678 
hexify(void * data,unsigned int len,char sep,bool upCase)679 String& String::hexify(void* data, unsigned int len, char sep, bool upCase)
680 {
681     const char* hex = upCase ? "0123456789ABCDEF" : "0123456789abcdef";
682     if (data && len) {
683 	const unsigned char* s = (const unsigned char*) data;
684 	unsigned int repeat = sep ? 3*len-1 : 2*len;
685 	// I know it's ugly to reuse but... copy/paste...
686 	char* data = (char*) ::malloc(repeat+1);
687 	if (data) {
688 	    char* d = data;
689 	    while (len--) {
690 		unsigned char c = *s++;
691 		*d++ = hex[(c >> 4) & 0x0f];
692 		*d++ = hex[c & 0x0f];
693 		if (sep)
694 		    *d++ = sep;
695 	    }
696 	    // wrote one too many - go back...
697 	    if (sep)
698 		d--;
699 	    *d = '\0';
700 	    char* odata = m_string;
701 	    m_string = data;
702 	    m_length = repeat;
703 	    changed();
704 	    if (odata)
705 		::free(odata);
706 	}
707 	else
708 	    Debug("String",DebugFail,"malloc(%d) returned NULL!",repeat+1);
709     }
710     else
711 	clear();
712     return *this;
713 }
714 
changed()715 void String::changed()
716 {
717     clearMatches();
718     m_hash = YSTRING_INIT_HASH;
719     if (!m_string)
720 	m_length = 0;
721     else if (!m_length)
722 	m_length = ::strlen(m_string);
723 }
724 
clear()725 void String::clear()
726 {
727     if (m_string) {
728 	char *odata = m_string;
729 	m_string = 0;
730 	changed();
731 	::free(odata);
732     }
733 }
734 
at(int index) const735 char String::at(int index) const
736 {
737     if ((index < 0) || ((unsigned)index >= m_length) || !m_string)
738 	return 0;
739     return m_string[index];
740 }
741 
substr(int offs,int len) const742 String String::substr(int offs, int len) const
743 {
744     if (offs < 0) {
745 	offs += m_length;
746 	if (offs < 0)
747 	    offs = 0;
748     }
749     if ((unsigned int)offs >= m_length)
750 	return String();
751     return String(c_str()+offs,len);
752 }
753 
toInteger(int defvalue,int base,int minvalue,int maxvalue,bool clamp) const754 int String::toInteger(int defvalue, int base, int minvalue, int maxvalue,
755     bool clamp) const
756 {
757     if (!m_string)
758 	return defvalue;
759     char *eptr = 0;
760     int val = strtoi(m_string,&eptr,base);
761     if (!eptr || *eptr)
762 	return defvalue;
763     if (val >= minvalue && val <= maxvalue)
764 	return val;
765     if (clamp)
766 	return (val < minvalue) ? minvalue : maxvalue;
767     return defvalue;
768 }
769 
toInteger(const TokenDict * tokens,int defvalue,int base) const770 int String::toInteger(const TokenDict* tokens, int defvalue, int base) const
771 {
772     if (!m_string)
773 	return defvalue;
774     if (tokens) {
775 	for (; tokens->token; tokens++)
776 	    if (operator==(tokens->token))
777 		return tokens->value;
778     }
779     return toInteger(defvalue,base);
780 }
781 
toLong(long int defvalue,int base,long int minvalue,long int maxvalue,bool clamp) const782 long int String::toLong(long int defvalue, int base, long int minvalue, long int maxvalue,
783     bool clamp) const
784 {
785     if (!m_string)
786 	return defvalue;
787     char *eptr = 0;
788 
789     errno = 0;
790     long int val = ::strtol(m_string,&eptr,base);
791     // on overflow/underflow mark the entire string as unreadable
792     if ((errno == ERANGE) && eptr)
793 	eptr = m_string;
794     if (!eptr || *eptr)
795 	return defvalue;
796     if (val >= minvalue && val <= maxvalue)
797 	return val;
798     if (clamp)
799 	return (val < minvalue) ? minvalue : maxvalue;
800     return defvalue;
801 }
802 
toInt64(int64_t defvalue,int base,int64_t minvalue,int64_t maxvalue,bool clamp) const803 int64_t String::toInt64(int64_t defvalue, int base, int64_t minvalue, int64_t maxvalue,
804     bool clamp) const
805 {
806     if (!m_string)
807 	return defvalue;
808     char *eptr = 0;
809 
810     errno = 0;
811     int64_t val = ::strtoll(m_string,&eptr,base);
812     // on overflow/underflow mark the entire string as unreadable
813     if ((errno == ERANGE) && eptr)
814 	eptr = m_string;
815     if (!eptr || *eptr)
816 	return defvalue;
817     if (val >= minvalue && val <= maxvalue)
818 	return val;
819     if (clamp)
820 	return (val < minvalue) ? minvalue : maxvalue;
821     return defvalue;
822 }
823 
toUInt64(uint64_t defvalue,int base,uint64_t minvalue,uint64_t maxvalue,bool clamp) const824 uint64_t String::toUInt64(uint64_t defvalue, int base, uint64_t minvalue, uint64_t maxvalue,
825     bool clamp) const
826 {
827     if (!m_string)
828 	return defvalue;
829     char *eptr = 0;
830 
831     errno = 0;
832     uint64_t val = ::strtoull(m_string,&eptr,base);
833     // on overflow/underflow mark the entire string as unreadable
834     if ((errno == ERANGE) && eptr)
835 	eptr = m_string;
836     if (!eptr || *eptr)
837 	return defvalue;
838     if (val >= minvalue && val <= maxvalue)
839 	return val;
840     if (clamp)
841 	return (val < minvalue) ? minvalue : maxvalue;
842     return defvalue;
843 }
844 
toDouble(double defvalue) const845 double String::toDouble(double defvalue) const
846 {
847     if (!m_string)
848 	return defvalue;
849     char *eptr = 0;
850     double val= ::strtod(m_string,&eptr);
851     if (!eptr || *eptr)
852 	return defvalue;
853     return val;
854 }
855 
856 static const char* str_false[] = { "false", "no", "off", "disable", "f", 0 };
857 static const char* str_true[] = { "true", "yes", "on", "enable", "t", 0 };
858 
toBoolean(bool defvalue) const859 bool String::toBoolean(bool defvalue) const
860 {
861     if (!m_string)
862 	return defvalue;
863     const char **test;
864     for (test=str_false; *test; test++)
865 	if (!::strcmp(m_string,*test))
866 	    return false;
867     for (test=str_true; *test; test++)
868 	if (!::strcmp(m_string,*test))
869 	    return true;
870     return defvalue;
871 }
872 
isBoolean() const873 bool String::isBoolean() const
874 {
875     if (!m_string)
876 	return false;
877     const char **test;
878     for (test=str_false; *test; test++)
879 	if (!::strcmp(m_string,*test))
880 	    return true;
881     for (test=str_true; *test; test++)
882 	if (!::strcmp(m_string,*test))
883 	    return true;
884     return false;
885 }
886 
toUpper()887 String& String::toUpper()
888 {
889     if (m_string) {
890 	char c;
891 	for (char *s = m_string; (c = *s); s++) {
892 	    if (('a' <= c) && (c <= 'z'))
893 		*s = c + 'A' - 'a';
894 	}
895     }
896     return *this;
897 }
898 
toLower()899 String& String::toLower()
900 {
901     if (m_string) {
902 	char c;
903 	for (char *s = m_string; (c = *s); s++) {
904 	    if (('A' <= c) && (c <= 'Z'))
905 		*s = c + 'a' - 'A';
906 	}
907     }
908     return *this;
909 }
910 
trimBlanks()911 String& String::trimBlanks()
912 {
913     if (m_string) {
914 	const char *s = m_string;
915 	while (*s == ' ' || *s == '\t')
916 	    s++;
917 	const char *e = s;
918 	for (const char *p = e; *p; p++)
919 	    if (*p != ' ' && *p != '\t')
920 		e = p+1;
921 	assign(s,e-s);
922     }
923     return *this;
924 }
925 
trimSpaces()926 String& String::trimSpaces()
927 {
928     if (m_string) {
929 	const char *s = m_string;
930 	while (*s == ' ' || *s == '\t' || *s == '\v' || *s == '\f' || *s == '\r' || *s == '\n')
931 	    s++;
932 	const char *e = s;
933 	for (const char *p = e; *p; p++)
934 	    if (*p != ' ' && *p != '\t' && *p != '\v' && *p != '\f' && *p != '\r' && *p != '\n')
935 		e = p+1;
936 	assign(s,e-s);
937     }
938     return *this;
939 }
940 
operator =(const char * value)941 String& String::operator=(const char* value)
942 {
943     if (value && !*value)
944 	value = 0;
945     if (value != c_str()) {
946 	char *tmp = m_string;
947 	m_string = value ? ::strdup(value) : 0;
948 	m_length = 0;
949 	if (value && !m_string)
950 	    Debug("String",DebugFail,"strdup() returned NULL!");
951 	changed();
952 	if (tmp)
953 	    ::free(tmp);
954     }
955     return *this;
956 }
957 
operator =(char value)958 String& String::operator=(char value)
959 {
960     char buf[2] = {value,0};
961     return operator=(buf);
962 }
963 
operator =(int32_t value)964 String& String::operator=(int32_t value)
965 {
966     char buf[16];
967     ::sprintf(buf,"%d",value);
968     return operator=(buf);
969 }
970 
operator =(uint32_t value)971 String& String::operator=(uint32_t value)
972 {
973     char buf[16];
974     ::sprintf(buf,"%u",value);
975     return operator=(buf);
976 }
977 
operator =(int64_t value)978 String& String::operator=(int64_t value)
979 {
980     char buf[24];
981     ::sprintf(buf,FMT64,value);
982     return operator=(buf);
983 }
984 
operator =(uint64_t value)985 String& String::operator=(uint64_t value)
986 {
987     char buf[24];
988     ::sprintf(buf,FMT64U,value);
989     return operator=(buf);
990 }
991 
operator =(double value)992 String& String::operator=(double value)
993 {
994     char buf[80];
995     ::sprintf(buf,"%g",value);
996     return operator=(buf);
997 }
998 
operator +=(char value)999 String& String::operator+=(char value)
1000 {
1001     char buf[2] = {value,0};
1002     return operator+=(buf);
1003 }
1004 
operator +=(int32_t value)1005 String& String::operator+=(int32_t value)
1006 {
1007     char buf[16];
1008     ::sprintf(buf,"%d",value);
1009     return operator+=(buf);
1010 }
1011 
operator +=(uint32_t value)1012 String& String::operator+=(uint32_t value)
1013 {
1014     char buf[16];
1015     ::sprintf(buf,"%u",value);
1016     return operator+=(buf);
1017 }
1018 
operator +=(int64_t value)1019 String& String::operator+=(int64_t value)
1020 {
1021     char buf[24];
1022     ::sprintf(buf,FMT64,value);
1023     return operator+=(buf);
1024 }
1025 
operator +=(uint64_t value)1026 String& String::operator+=(uint64_t value)
1027 {
1028     char buf[24];
1029     ::sprintf(buf,FMT64U,value);
1030     return operator+=(buf);
1031 }
1032 
operator +=(double value)1033 String& String::operator+=(double value)
1034 {
1035     char buf[80];
1036     ::sprintf(buf,"%g",value);
1037     return operator+=(buf);
1038 }
1039 
operator >>(const char * skip)1040 String& String::operator>>(const char* skip)
1041 {
1042     if (m_string && skip && *skip) {
1043 	const char *loc = ::strstr(m_string,skip);
1044 	if (loc)
1045 	    assign(loc+::strlen(skip));
1046     }
1047     return *this;
1048 }
1049 
operator >>(char & store)1050 String& String::operator>>(char& store)
1051 {
1052     if (m_string) {
1053 	store = m_string[0];
1054 	assign(m_string+1);
1055     }
1056     return *this;
1057 }
1058 
operator >>(UChar & store)1059 String& String::operator>>(UChar& store)
1060 {
1061     const char* str = m_string;
1062     store.decode(str);
1063     assign(str);
1064     return *this;
1065 }
1066 
operator >>(int & store)1067 String& String::operator>>(int& store)
1068 {
1069     if (m_string) {
1070 	char *end = 0;
1071 	int l = strtoi(m_string,&end,0);
1072 	if (end && (m_string != end)) {
1073 	    store = l;
1074 	    assign(end);
1075 	}
1076     }
1077     return *this;
1078 }
1079 
operator >>(unsigned int & store)1080 String& String::operator>>(unsigned int& store)
1081 {
1082     if (m_string) {
1083 	char *end = 0;
1084 	errno = 0;
1085 	unsigned long int l = ::strtoul(m_string,&end,0);
1086 #if UINT_MAX != ULONG_MAX
1087 	if (l > UINT_MAX) {
1088 	    l = UINT_MAX;
1089 	    errno = ERANGE;
1090 	}
1091 #endif
1092 	if (!errno && end && (m_string != end)) {
1093 	    store = l;
1094 	    assign(end);
1095 	}
1096     }
1097     return *this;
1098 }
1099 
operator >>(bool & store)1100 String& String::operator>>(bool& store)
1101 {
1102     if (m_string) {
1103 	const char *s = m_string;
1104 	while (*s == ' ' || *s == '\t')
1105 	    s++;
1106 	const char **test;
1107 	for (test=str_false; *test; test++) {
1108 	    int l = ::strlen(*test);
1109 	    if (!::strncmp(s,*test,l) && isWordBreak(s[l],true)) {
1110 		store = false;
1111 		assign(s+l);
1112 		return *this;
1113 	    }
1114 	}
1115 	for (test=str_true; *test; test++) {
1116 	    int l = ::strlen(*test);
1117 	    if (!::strncmp(s,*test,l) && isWordBreak(s[l],true)) {
1118 		store = true;
1119 		assign(s+l);
1120 		return *this;
1121 	    }
1122 	}
1123     }
1124     return *this;
1125 }
1126 
append(const char * value,int len)1127 String& String::append(const char* value, int len)
1128 {
1129     if (len && value && *value) {
1130 	if (len < 0) {
1131 	    if (!m_string) {
1132 		m_string = ::strdup(value);
1133 		m_length = 0;
1134 		if (!m_string)
1135 		    Debug("String",DebugFail,"strdup() returned NULL!");
1136 		changed();
1137 		return *this;
1138 	    }
1139 	    len = ::strlen(value);
1140 	}
1141 	int olen = length();
1142 	len += olen;
1143 	char *tmp1 = m_string;
1144 	char *tmp2 = (char *) ::malloc(len+1);
1145 	if (tmp2) {
1146 	    if (m_string)
1147 		::strncpy(tmp2,m_string,olen);
1148 	    ::strncpy(tmp2+olen,value,len-olen);
1149 	    tmp2[len] = 0;
1150 	    m_string = tmp2;
1151 	    m_length = len;
1152 	    ::free(tmp1);
1153 	}
1154 	else
1155 	    Debug("String",DebugFail,"malloc(%d) returned NULL!",len+1);
1156 	changed();
1157     }
1158     return *this;
1159 }
1160 
append(const char * value,const char * separator,bool force)1161 String& String::append(const char* value, const char* separator, bool force)
1162 {
1163     if (value || force) {
1164 	if (!null())
1165 	    operator+=(separator);
1166 	operator+=(value);
1167     }
1168     return *this;
1169 }
1170 
append(const ObjList * list,const char * separator,bool force)1171 String& String::append(const ObjList* list, const char* separator, bool force)
1172 {
1173     if (!list)
1174 	return *this;
1175     int olen = length();
1176     int sepLen = 0;
1177     if (!TelEngine::null(separator))
1178 	sepLen = ::strlen(separator);
1179     int len = 0;
1180     for (ObjList* o = list->skipNull(); o; o = o->skipNext()) {
1181 	const String& src = o->get()->toString();
1182 	if (sepLen && (len || olen) && (src.length() || force))
1183 	    len += sepLen;
1184 	len += src.length();
1185     }
1186     if (!len)
1187 	return *this;
1188     char* oldStr = m_string;
1189     char* newStr = (char*)::malloc(olen + len + 1);
1190     if (!newStr) {
1191 	Debug("String",DebugFail,"malloc(%d) returned NULL!",olen + len + 1);
1192 	return *this;
1193     }
1194     if (m_string)
1195 	::memcpy(newStr,m_string,olen);
1196     for (list = list->skipNull(); list; list = list->skipNext()) {
1197 	const String& src = list->get()->toString();
1198 	if (sepLen && olen && (src.length() || force)) {
1199 	    ::memcpy(newStr + olen,separator,sepLen);
1200 	    olen += sepLen;
1201 	}
1202 	::memcpy(newStr + olen,src.c_str(),src.length());
1203 	olen += src.length();
1204     }
1205     newStr[olen] = 0;
1206     m_string = newStr;
1207     m_length = olen;
1208     ::free(oldStr);
1209     changed();
1210     return *this;
1211 }
1212 
append(double value,unsigned int decimals)1213 String& String::append(double value, unsigned int decimals)
1214 {
1215     if (decimals > 12)
1216 	decimals = 12;
1217     char buf[80];
1218     ::sprintf(buf,"%0.*f",decimals,value);
1219     return operator+=(buf);
1220 }
1221 
string_printf(unsigned int & length,const char * format,va_list & va)1222 static char* string_printf(unsigned int& length, const char* format, va_list& va)
1223 {
1224     if (TelEngine::null(format) || !length)
1225 	return 0;
1226     char* buf = (char*)::malloc(length + 1);
1227     if (!buf) {
1228 	Debug("String",DebugFail,"malloc(%d) returned NULL!",length);
1229 	return 0;
1230     }
1231     // Remember vsnprintf:
1232     // standard:
1233     //  - buffer size and returned value include the terminating NULL char
1234     //  - returns -1 on error
1235     // Windows:
1236     //  - it doesn't write terminating NULL if there is no space
1237     //  - returns -1 on error or buffer length is less than number of bytes to write
1238     //  - returned value doesn't include the terminating NULL char (even if it was written to output)
1239     buf[length] = 0;
1240 #ifdef _WINDOWS
1241     errno = 0;
1242     int len = ::vsnprintf(buf,length,format,va);
1243 #else
1244     int len = ::vsnprintf(buf,length + 1,format,va);
1245 #endif
1246     if (len < 0) {
1247 #ifdef _WINDOWS
1248 	if (errno == ERANGE) {
1249 	    XDebug("String",DebugCrit,"string_printf() incomplete write");
1250 	    buf[length] = 0;
1251 	    length = 0;
1252 	    return buf;
1253 	}
1254 #endif
1255 	::free(buf);
1256 	Debug("String",DebugCrit,"string_printf(): vsnprintf() failed!");
1257 	return 0;
1258     }
1259     if (len < (int)length)
1260 	length = len;
1261 #ifdef XDEBUG
1262     else if (len > (int)length || buf[len])
1263 	Debug("String",DebugCrit,"string_printf() incomplete write");
1264 #endif
1265     buf[length] = 0;
1266     return buf;
1267 }
1268 
printf(unsigned int length,const char * format,...)1269 String& String::printf(unsigned int length, const char* format,  ...)
1270 {
1271     va_list va;
1272     va_start(va,format);
1273     char* buf = string_printf(length,format,va);
1274     va_end(va);
1275     if (!buf) {
1276 	clear();
1277 	return *this;
1278     }
1279     char* old = m_string;
1280     m_string = buf;
1281     m_length = length;
1282     ::free(old);
1283     changed();
1284     return *this;
1285 }
1286 
printf(const char * format,...)1287 String& String::printf(const char* format, ...)
1288 {
1289     va_list va;
1290     va_start(va,format);
1291     unsigned int len = TelEngine::null(format) ? 0 : (128 + ::strlen(format));
1292     char* buf = string_printf(len,format,va);
1293     va_end(va);
1294     if (!buf) {
1295 	clear();
1296 	return *this;
1297     }
1298     char* old = m_string;
1299     m_string = buf;
1300     m_length = len;
1301     ::free(old);
1302     changed();
1303     return *this;
1304 }
1305 
appendFixed(unsigned int fixedLength,const char * str,unsigned int len,char fill,int align)1306 String& String::appendFixed(unsigned int fixedLength, const char* str, unsigned int len, char fill, int align)
1307 {
1308     if (len == (unsigned int)-1)
1309 	len = ::strlen(str);
1310     if (!str || len == 0)
1311 	return *this;
1312     int alignPos = 0;
1313     if (len < fixedLength) {
1314 	if (align == Center)
1315 	    alignPos = fixedLength / 2 - len / 2;
1316 	else if (align == Right)
1317 	    alignPos = fixedLength - len;
1318     } else
1319 	len = fixedLength;
1320     char* buf = (char*)::malloc(fixedLength + 1);
1321     if (!buf) {
1322 	Debug("String",DebugFail,"malloc(%d) returned NULL!",fixedLength + 1);
1323 	return *this;
1324     }
1325     ::memset(buf,fill,fixedLength);
1326     ::memcpy(buf + alignPos,str,len);
1327     buf[fixedLength] = 0;
1328     operator+=(buf);
1329     ::free(buf);
1330     return *this;
1331 }
1332 
operator ==(const char * value) const1333 bool String::operator==(const char* value) const
1334 {
1335     if (!m_string)
1336 	return !(value && *value);
1337     return value && !::strcmp(m_string,value);
1338 }
1339 
operator !=(const char * value) const1340 bool String::operator!=(const char* value) const
1341 {
1342     if (!m_string)
1343 	return value && *value;
1344     return (!value) || ::strcmp(m_string,value);
1345 }
1346 
operator &=(const char * value) const1347 bool String::operator&=(const char* value) const
1348 {
1349     if (!m_string)
1350 	return !(value && *value);
1351     return value && !::strcasecmp(m_string,value);
1352 }
1353 
operator |=(const char * value) const1354 bool String::operator|=(const char* value) const
1355 {
1356     if (!m_string)
1357 	return value && *value;
1358     return (!value) || ::strcasecmp(m_string,value);
1359 }
1360 
find(char what,unsigned int offs) const1361 int String::find(char what, unsigned int offs) const
1362 {
1363     if (!m_string || (offs > m_length))
1364 	return -1;
1365     const char *s = ::strchr(m_string+offs,what);
1366     return s ? s-m_string : -1;
1367 }
1368 
find(const char * what,unsigned int offs) const1369 int String::find(const char* what, unsigned int offs) const
1370 {
1371     if (!(m_string && what && *what) || (offs > m_length))
1372 	return -1;
1373     const char *s = ::strstr(m_string+offs,what);
1374     return s ? s-m_string : -1;
1375 }
1376 
rfind(char what) const1377 int String::rfind(char what) const
1378 {
1379     if (!m_string)
1380 	return -1;
1381     const char *s = ::strrchr(m_string,what);
1382     return s ? s-m_string : -1;
1383 }
1384 
rfind(const char * what) const1385 int String::rfind(const char* what) const
1386 {
1387     int ret = -1;
1388     for (int pos = -1; (pos = find(what,pos + 1)) >= 0;)
1389 	ret = pos;
1390     return ret;
1391 }
1392 
startsWith(const char * what,bool wordBreak,bool caseInsensitive) const1393 bool String::startsWith(const char* what, bool wordBreak, bool caseInsensitive) const
1394 {
1395     if (!(m_string && what && *what))
1396 	return false;
1397     unsigned int l = ::strlen(what);
1398     if (m_length < l)
1399 	return false;
1400     else if (wordBreak && (m_length > l) && !isWordBreak(m_string[l]))
1401 	return false;
1402 
1403     if (caseInsensitive)
1404 	return (::strncasecmp(m_string,what,l) == 0);
1405     return (::strncmp(m_string,what,l) == 0);
1406 }
1407 
startSkip(const char * what,bool wordBreak,bool caseInsensitive)1408 bool String::startSkip(const char* what, bool wordBreak, bool caseInsensitive)
1409 {
1410     if (startsWith(what,wordBreak,caseInsensitive)) {
1411 	const char *p = m_string + ::strlen(what);
1412 	if (wordBreak)
1413 	    while (isWordBreak(*p))
1414 		p++;
1415 	assign(p);
1416 	return true;
1417     }
1418     return false;
1419 }
1420 
endsWith(const char * what,bool wordBreak,bool caseInsensitive) const1421 bool String::endsWith(const char* what, bool wordBreak, bool caseInsensitive) const
1422 {
1423     if (!(m_string && what && *what))
1424 	return false;
1425     unsigned int l = ::strlen(what);
1426     if (m_length < l)
1427 	return false;
1428     else if (wordBreak && (m_length > l) && !isWordBreak(m_string[m_length-l-1]))
1429 	return false;
1430     if (caseInsensitive)
1431 	return (::strncasecmp(m_string+m_length-l,what,l) == 0);
1432     return (::strncmp(m_string+m_length-l,what,l) == 0);
1433 }
1434 
extractTo(const char * sep,String & str)1435 String& String::extractTo(const char* sep, String& str)
1436 {
1437     int pos = find(sep);
1438     if (pos >= 0) {
1439 	str = substr(0,pos);
1440 	assign(m_string+pos+::strlen(sep));
1441     }
1442     else {
1443 	str = *this;
1444 	clear();
1445     }
1446     return *this;
1447 }
1448 
extractTo(const char * sep,bool & store)1449 String& String::extractTo(const char* sep, bool& store)
1450 {
1451     String str;
1452     extractTo(sep,str);
1453     store = str.toBoolean(store);
1454     return *this;
1455 }
1456 
extractTo(const char * sep,int & store,int base)1457 String& String::extractTo(const char* sep, int& store, int base)
1458 {
1459     String str;
1460     extractTo(sep,str);
1461     store = str.toInteger(store,base);
1462     return *this;
1463 }
1464 
extractTo(const char * sep,int & store,const TokenDict * tokens,int base)1465 String& String::extractTo(const char* sep, int& store, const TokenDict* tokens, int base)
1466 {
1467     String str;
1468     extractTo(sep,str);
1469     store = str.toInteger(tokens,store,base);
1470     return *this;
1471 }
1472 
extractTo(const char * sep,double & store)1473 String& String::extractTo(const char* sep, double& store)
1474 {
1475     String str;
1476     extractTo(sep,str);
1477     store = str.toDouble(store);
1478     return *this;
1479 }
1480 
matches(const Regexp & rexp)1481 bool String::matches(const Regexp& rexp)
1482 {
1483     if (m_matches)
1484 	clearMatches();
1485     else
1486 	m_matches = new StringMatchPrivate;
1487     if (rexp.matches(c_str(),m_matches)) {
1488 	m_matches->fixup();
1489 	return true;
1490     }
1491     return false;
1492 }
1493 
matchOffset(int index) const1494 int String::matchOffset(int index) const
1495 {
1496     if ((!m_matches) || (index < 0) || (index > m_matches->count))
1497 	return -1;
1498     return m_matches->rmatch[index].rm_so;
1499 }
1500 
matchLength(int index) const1501 int String::matchLength(int index) const
1502 {
1503     if ((!m_matches) || (index < 0) || (index > m_matches->count))
1504 	return 0;
1505     return m_matches->rmatch[index].rm_eo;
1506 }
1507 
matchCount() const1508 int String::matchCount() const
1509 {
1510     if (!m_matches)
1511 	return 0;
1512     return m_matches->count;
1513 }
1514 
replaceMatches(const String & templ) const1515 String String::replaceMatches(const String& templ) const
1516 {
1517     String s;
1518     int pos, ofs = 0;
1519     for (;;) {
1520 	pos = templ.find('\\',ofs);
1521 	if (pos < 0) {
1522 	    s << templ.substr(ofs);
1523 	    break;
1524 	}
1525 	s << templ.substr(ofs,pos-ofs);
1526 	pos++;
1527 	char c = templ[pos];
1528 	if (c == '\\') {
1529 	    pos++;
1530 	    s << "\\";
1531 	}
1532 	else if ('0' <= c && c <= '9') {
1533 	    pos++;
1534 	    s << matchString(c - '0');
1535 	}
1536 	else {
1537 	    pos++;
1538 	    s << "\\" << c;
1539 	}
1540 	ofs = pos;
1541     }
1542     return s;
1543 }
1544 
clearMatches()1545 void String::clearMatches()
1546 {
1547     if (m_matches)
1548 	m_matches->clear();
1549 }
1550 
split(char separator,bool emptyOK) const1551 ObjList* String::split(char separator, bool emptyOK) const
1552 {
1553     ObjList* list = new ObjList;
1554     ObjList* dest = list;
1555     int p = 0;
1556     int s;
1557     while ((s = find(separator,p)) >= 0) {
1558 	if (emptyOK || (s > p))
1559 	    dest = dest->append(new String(m_string+p,s-p));
1560 	p = s + 1;
1561     }
1562     if (emptyOK || (m_string && m_string[p]))
1563 	dest->append(new String(m_string+p));
1564     return list;
1565 }
1566 
split(const Regexp & reg,bool emptyOK) const1567 ObjList* String::split(const Regexp& reg, bool emptyOK) const
1568 {
1569     String s = *this;
1570     ObjList* list = new ObjList;
1571     ObjList* dest = list;
1572     while (true) {
1573 	if (!(s && s.matches(reg))) {
1574 	    if (s || emptyOK)
1575 		dest = dest->append(new String(s));
1576 	    break;
1577 	}
1578 	int pos = s.matchOffset(0);
1579 	if (emptyOK || pos > 0)
1580 	    dest = dest->append(new String(s.c_str(),pos));
1581 	s = s.substr(pos + s.matchLength(0));
1582     }
1583     return list;
1584 }
1585 
msgEscape(const char * str,char extraEsc)1586 String String::msgEscape(const char* str, char extraEsc)
1587 {
1588     String s;
1589     if (TelEngine::null(str))
1590 	return s;
1591     char c;
1592     const char* pos = str;
1593     char buff[3] =  {'%', '%', '\0'};
1594     while ((c=*pos++)) {
1595 	if ((unsigned char)c < ' ' || c == ':' || c == extraEsc)
1596 	    c += '@';
1597 	else if (c != '%')
1598 	    continue;
1599 	buff[1] = c;
1600 	s.append(str,pos - str - 1);
1601 	s += buff;
1602 	str = pos;
1603     }
1604     s += str;
1605     return s;
1606 }
1607 
msgUnescape(const char * str,int * errptr,char extraEsc)1608 String String::msgUnescape(const char* str, int* errptr, char extraEsc)
1609 {
1610     String s;
1611     if (TelEngine::null(str))
1612 	return s;
1613     if (extraEsc)
1614 	extraEsc += '@';
1615     const char *pos = str;
1616     char c;
1617     while ((c=*pos++)) {
1618 	if ((unsigned char)c < ' ') {
1619 	    if (errptr)
1620 		*errptr = (pos-str) - 1;
1621 	    s.append(str,pos - str - 1);
1622 	    return s;
1623 	}
1624 	else if (c == '%') {
1625 	    c=*pos++;
1626 	    if ((c > '@' && c <= '_') || c == 'z' || c == extraEsc)
1627 		c -= '@';
1628 	    else if (c != '%') {
1629 		if (errptr)
1630 		    *errptr = (pos-str) - 1;
1631 		s.append(str,pos - str - 1);
1632 		return s;
1633 	    }
1634 	    s.append(str,pos - str - 2);
1635 	    s += c;
1636 	    str = pos;
1637 	}
1638     }
1639     s += str;
1640     if (errptr)
1641 	*errptr = -1;
1642     return s;
1643 }
1644 
sqlEscape(const char * str,char extraEsc)1645 String String::sqlEscape(const char* str, char extraEsc)
1646 {
1647     String s;
1648     if (TelEngine::null(str))
1649 	return s;
1650     char c;
1651     while ((c=*str++)) {
1652 	if (c == '\'')
1653 	    s += "'";
1654 	else if (c == '\\' || c == extraEsc)
1655 	    s += "\\";
1656 	s += c;
1657     }
1658     return s;
1659 }
1660 
uriEscape(const char * str,char extraEsc,const char * noEsc)1661 String String::uriEscape(const char* str, char extraEsc, const char* noEsc)
1662 {
1663     String s;
1664     if (TelEngine::null(str))
1665 	return s;
1666     char c;
1667     while ((c=*str++)) {
1668 	if ((unsigned char)c < ' ' || c == '%' || c == extraEsc ||
1669 	    ((c == ' ' || c == '+' || c == '?' || c == '&') && !(noEsc && ::strchr(noEsc,c))))
1670 	    s << '%' << hexEncode(c >> 4) << hexEncode(c);
1671 	else
1672 	    s += c;
1673     }
1674     return s;
1675 }
1676 
uriEscape(const char * str,const char * extraEsc,const char * noEsc)1677 String String::uriEscape(const char* str, const char* extraEsc, const char* noEsc)
1678 {
1679     String s;
1680     if (TelEngine::null(str))
1681 	return s;
1682     char c;
1683     while ((c=*str++)) {
1684 	if ((unsigned char)c < ' ' || c == '%' || (extraEsc && ::strchr(extraEsc,c)) ||
1685 	    ((c == ' ' || c == '+' || c == '?' || c == '&') && !(noEsc && ::strchr(noEsc,c))))
1686 	    s << '%' << hexEncode(c >> 4) << hexEncode(c);
1687 	else
1688 	    s += c;
1689     }
1690     return s;
1691 }
1692 
uriUnescape(const char * str,int * errptr)1693 String String::uriUnescape(const char* str, int* errptr)
1694 {
1695     String s;
1696     if (TelEngine::null(str))
1697 	return s;
1698     const char *pos = str;
1699     char c;
1700     while ((c=*pos++)) {
1701 	if ((unsigned char)c < ' ') {
1702 	    if (errptr)
1703 		*errptr = (pos-str) - 1;
1704 	    return s;
1705 	}
1706 	else if (c == '%') {
1707 	    int hiNibble = hexDecode(*pos++);
1708 	    if (hiNibble < 0) {
1709 		if (errptr)
1710 		    *errptr = (pos-str) - 1;
1711 		return s;
1712 	    }
1713 	    int loNibble = hexDecode(*pos++);
1714 	    if (loNibble < 0) {
1715 		if (errptr)
1716 		    *errptr = (pos-str) - 1;
1717 		return s;
1718 	    }
1719 	    c = ((hiNibble << 4) | loNibble) & 0xff;
1720 	}
1721 	s += c;
1722     }
1723     if (errptr)
1724 	*errptr = -1;
1725     return s;
1726 }
1727 
hash(const char * value,unsigned int h)1728 unsigned int String::hash(const char* value, unsigned int h)
1729 {
1730     if (!value)
1731 	return 0;
1732 
1733     // sdbm hash algorithm, hash(i) = hash(i-1) * 65599 + str[i]
1734     while (unsigned char c = (unsigned char) *value++)
1735 	h = (h << 6) + (h << 16) - h + c;
1736     return h;
1737 }
1738 
lenUtf8(const char * value,uint32_t maxChar,bool overlong)1739 int String::lenUtf8(const char* value, uint32_t maxChar, bool overlong)
1740 {
1741     if (!value)
1742 	return 0;
1743     if (maxChar < 128)
1744 	maxChar = 0x10ffff; // RFC 3629 default limit
1745 
1746     int count = 0;
1747     unsigned int more = 0;
1748     uint32_t min = 0;
1749     uint32_t val = 0;
1750 
1751     while (unsigned char c = (unsigned char) *value++) {
1752 	if (more) {
1753 	    // all continuation bytes are in range [128..191]
1754 	    if ((c & 0xc0) != 0x80)
1755 		return -1;
1756 	    val = (val << 6) | (c & 0x3f);
1757 	    if (!--more) {
1758 		// got full value, check for overlongs and out of range
1759 		if (val > maxChar)
1760 		    return -1;
1761 		if (overlong)
1762 		    continue;
1763 		if (val < min)
1764 		    return -1;
1765 	    }
1766 	    continue;
1767 	}
1768 	count++;
1769 	// from 1st byte we find out how many are supposed to follow
1770 	if (c < 0x80)      // 1 byte, 0...0x7F, ASCII characters, no check
1771 	    ;
1772 	else if (c < 0xc0) // invalid as first UFT-8 byte
1773 	    return -1;
1774 	else if (c < 0xe0) {
1775 	    // 2 bytes, 0x80...0x7FF
1776 	    min = 0x80;
1777 	    val = c & 0x1f;
1778 	    more = 1;
1779 	}
1780 	else if (c < 0xf0) {
1781 	    // 3 bytes, 0x800...0xFFFF, Basic Multilingual Plane
1782 	    min = 0x800;
1783 	    val = c & 0x0f;
1784 	    more = 2;
1785 	}
1786 	else if (c < 0xf8) {
1787 	    // 4 bytes, 0x10000...0x1FFFFF, RFC 3629 limit (10FFFF)
1788 	    min = 0x10000;
1789 	    val = c & 0x07;
1790 	    more = 3;
1791 	}
1792 	else if (c < 0xfc) {
1793 	    // 5 bytes, 0x200000...0x3FFFFFF
1794 	    min = 0x200000;
1795 	    val = c & 0x03;
1796 	    more = 4;
1797 	}
1798 	else if (c < 0xfe) {
1799 	    // 6 bytes, 0x4000000...0x7FFFFFFF
1800 	    min = 0x4000000;
1801 	    val = c & 0x01;
1802 	    more = 5;
1803 	}
1804 	else
1805 	    return -1;
1806     }
1807     if (more)
1808 	return -1;
1809     return count;
1810 }
1811 
fixUtf8(const char * replace,uint32_t maxChar,bool overlong)1812 int String::fixUtf8(const char* replace, uint32_t maxChar, bool overlong)
1813 {
1814     if (null())
1815 	return 0;
1816     if (maxChar < 128)
1817 	maxChar = 0x10ffff; // RFC 3629 default limit
1818     if (!replace)
1819 	replace = "\xEF\xBF\xBD";
1820 
1821     int count = 0;
1822     unsigned int more = 0;
1823     uint32_t min = 0;
1824     uint32_t val = 0;
1825     unsigned int pos = 0;
1826     bool bad = false;
1827     String tmp;
1828 
1829     for (unsigned int i = 0; i < m_length; i++) {
1830 	unsigned char c = (unsigned char) at(i);
1831 	if (more) {
1832 	    // all continuation bytes are in range [128..191]
1833 	    if ((c & 0xc0) != 0x80) {
1834 		// truncated sequence, must search for 1st byte again
1835 		more = 0;
1836 		count++;
1837 		tmp += replace;
1838 	    }
1839 	    else {
1840 		val = (val << 6) | (c & 0x3f);
1841 		if (!--more) {
1842 		    // got full value, check for overlongs and out of range
1843 		    if ((val > maxChar) || ((val < min) && !overlong))
1844 			bad = true;
1845 		    // finished multibyte, add it to temporary
1846 		    if (bad) {
1847 			count++;
1848 			tmp += replace;
1849 		    }
1850 		    else
1851 			tmp += substr(pos,(int)(i+1-pos));
1852 		}
1853 		continue;
1854 	    }
1855 	}
1856 	pos = i;
1857 	bad = false;
1858 	// from 1st byte we find out how many are supposed to follow
1859 	if (c < 0x80)      // 1 byte, 0...0x7F, ASCII characters, good
1860 	    ;
1861 	else if (c < 0xc0) // invalid as first UFT-8 byte
1862 	    bad = true;
1863 	else if (c < 0xe0) {
1864 	    // 2 bytes, 0x80...0x7FF
1865 	    min = 0x80;
1866 	    val = c & 0x1f;
1867 	    more = 1;
1868 	}
1869 	else if (c < 0xf0) {
1870 	    // 3 bytes, 0x800...0xFFFF, Basic Multilingual Plane
1871 	    min = 0x800;
1872 	    val = c & 0x0f;
1873 	    more = 2;
1874 	}
1875 	else if (c < 0xf8) {
1876 	    // 4 bytes, 0x10000...0x1FFFFF, RFC 3629 limit (10FFFF)
1877 	    min = 0x10000;
1878 	    val = c & 0x07;
1879 	    more = 3;
1880 	}
1881 	else if (c < 0xfc) {
1882 	    // 5 bytes, 0x200000...0x3FFFFFF
1883 	    min = 0x200000;
1884 	    val = c & 0x03;
1885 	    more = 4;
1886 	}
1887 	else if (c < 0xfe) {
1888 	    // 6 bytes, 0x4000000...0x7FFFFFFF
1889 	    min = 0x4000000;
1890 	    val = c & 0x01;
1891 	    more = 5;
1892 	}
1893 	else
1894 	    bad = true;
1895 	if (!more) {
1896 	    if (bad) {
1897 		count++;
1898 		tmp += replace;
1899 	    }
1900 	    else
1901 		tmp += (char)c;
1902 	}
1903     }
1904     if (more) {
1905 	// UTF-8 truncated at end of string
1906 	count++;
1907 	tmp += replace;
1908     }
1909 
1910     if (count)
1911 	operator=(tmp);
1912     return count;
1913 }
1914 
getObject(const String & name) const1915 void* String::getObject(const String& name) const
1916 {
1917     if (name == YATOM("String"))
1918 	return const_cast<String*>(this);
1919     return GenObject::getObject(name);
1920 }
1921 
toString() const1922 const String& String::toString() const
1923 {
1924     return *this;
1925 }
1926 
atom(const String * & str,const char * val)1927 const String* String::atom(const String*& str, const char* val)
1928 {
1929     if (!str) {
1930 	s_mutex.lock();
1931 	if (!str) {
1932 	    if (TelEngine::null(val))
1933 		str = &s_empty;
1934 	    else {
1935 		str = static_cast<const String*>(s_atoms[val]);
1936 		if (!str) {
1937 		    str = new String(val);
1938 		    s_atoms.insert(str);
1939 		}
1940 	    }
1941 	}
1942 	s_mutex.unlock();
1943     }
1944     return str;
1945 }
1946 
1947 
Regexp()1948 Regexp::Regexp()
1949     : m_regexp(0), m_compile(true), m_flags(0)
1950 {
1951     XDebug(DebugAll,"Regexp::Regexp() [%p]",this);
1952 }
1953 
Regexp(const char * value,bool extended,bool insensitive)1954 Regexp::Regexp(const char* value, bool extended, bool insensitive)
1955     : String(value), m_regexp(0), m_compile(true), m_flags(0)
1956 {
1957     XDebug(DebugAll,"Regexp::Regexp(\"%s\",%d,%d) [%p]",
1958 	value,extended,insensitive,this);
1959     setFlags(extended,insensitive);
1960     compile();
1961 }
1962 
Regexp(const Regexp & value)1963 Regexp::Regexp(const Regexp& value)
1964     : String(value.c_str()), m_regexp(0), m_compile(true), m_flags(value.m_flags)
1965 {
1966     XDebug(DebugAll,"Regexp::Regexp(%p) [%p]",&value,this);
1967 }
1968 
~Regexp()1969 Regexp::~Regexp()
1970 {
1971     cleanup();
1972 }
1973 
matches(const char * value,StringMatchPrivate * matchlist) const1974 bool Regexp::matches(const char* value, StringMatchPrivate* matchlist) const
1975 {
1976     XDebug(DebugInfo,"Regexp::matches(\"%s\",%p)",value,matchlist);
1977     if (!value)
1978 	value = "";
1979     if (!compile())
1980 	return false;
1981     int mm = matchlist ? MAX_MATCH : 0;
1982     regmatch_t *mt = matchlist ? (matchlist->rmatch)+1 : 0;
1983     return !::regexec((regex_t *)m_regexp,value,mm,mt,0);
1984 }
1985 
matches(const char * value) const1986 bool Regexp::matches(const char* value) const
1987 {
1988     return matches(value,0);
1989 }
1990 
changed()1991 void Regexp::changed()
1992 {
1993     cleanup();
1994     String::changed();
1995 }
1996 
doCompile() const1997 bool Regexp::doCompile() const
1998 {
1999     XDebug(DebugInfo,"Regexp::compile()");
2000     m_compile = false;
2001     if (c_str() && !m_regexp) {
2002 	regex_t *data = (regex_t *) ::malloc(sizeof(regex_t));
2003 	if (!data) {
2004 	    Debug("Regexp",DebugFail,"malloc(%d) returned NULL!",(int)sizeof(regex_t));
2005 	    return false;
2006 	}
2007 	if (::regcomp(data,c_str(),m_flags)) {
2008 	    Debug(DebugWarn,"Regexp::compile() \"%s\" failed",c_str());
2009 	    ::regfree(data);
2010 	    ::free(data);
2011 	}
2012 	else
2013 	    m_regexp = (void *)data;
2014     }
2015     return (m_regexp != 0);
2016 }
2017 
cleanup()2018 void Regexp::cleanup()
2019 {
2020     XDebug(DebugInfo,"Regexp::cleanup()");
2021     if (m_regexp) {
2022 	regex_t *data = (regex_t *)m_regexp;
2023 	m_regexp = 0;
2024 	::regfree(data);
2025 	::free(data);
2026     }
2027     m_compile = true;
2028 }
2029 
setFlags(bool extended,bool insensitive)2030 void Regexp::setFlags(bool extended, bool insensitive)
2031 {
2032     int f = (extended ? REG_EXTENDED : 0) | (insensitive ? REG_ICASE : 0);
2033     if (m_flags != f) {
2034 	cleanup();
2035 	m_flags = f;
2036     }
2037 }
2038 
isExtended() const2039 bool Regexp::isExtended() const
2040 {
2041     return (m_flags & REG_EXTENDED) != 0;
2042 }
2043 
isCaseInsensitive() const2044 bool Regexp::isCaseInsensitive() const
2045 {
2046     return (m_flags & REG_ICASE) != 0;
2047 }
2048 
2049 
NamedString(const char * name,const char * value)2050 NamedString::NamedString(const char* name, const char* value)
2051     : String(value), m_name(name)
2052 {
2053     XDebug(DebugAll,"NamedString::NamedString(\"%s\",\"%s\") [%p]",name,value,this);
2054 }
2055 
toString() const2056 const String& NamedString::toString() const
2057 {
2058     return m_name;
2059 }
2060 
getObject(const String & name) const2061 void* NamedString::getObject(const String& name) const
2062 {
2063     if (name == YATOM("NamedString"))
2064 	return (void*)this;
2065     return String::getObject(name);
2066 }
2067 
2068 
NamedPointer(const char * name,GenObject * data,const char * value)2069 NamedPointer::NamedPointer(const char* name, GenObject* data, const char* value)
2070     : NamedString(name,value),
2071     m_data(0)
2072 {
2073     userData(data);
2074 }
2075 
~NamedPointer()2076 NamedPointer::~NamedPointer()
2077 {
2078     userData(0);
2079 }
2080 
2081 // Set obscure data carried by this object.
userData(GenObject * data)2082 void NamedPointer::userData(GenObject* data)
2083 {
2084     TelEngine::destruct(m_data);
2085     m_data = data;
2086 }
2087 
2088 // Retrieve the pointer carried by this object and release ownership
takeData()2089 GenObject* NamedPointer::takeData()
2090 {
2091     GenObject* tmp = m_data;
2092     m_data = 0;
2093     return tmp;
2094 }
2095 
getObject(const String & name) const2096 void* NamedPointer::getObject(const String& name) const
2097 {
2098     if (name == YATOM("NamedPointer"))
2099 	return (void*)this;
2100     void* p = NamedString::getObject(name);
2101     if (p)
2102 	return p;
2103     if (m_data)
2104 	return m_data->getObject(name);
2105     return 0;
2106 }
2107 
2108 // Called whenever the string value changed. Release the pointer
changed()2109 void NamedPointer::changed()
2110 {
2111     userData(0);
2112     NamedString::changed();
2113 }
2114 
2115 
getObject(const String & name) const2116 void* GenObject::getObject(const String& name) const
2117 {
2118     return 0;
2119 }
2120 
toString() const2121 const String& GenObject::toString() const
2122 {
2123     return String::empty();
2124 }
2125 
traceId() const2126 const String& GenObject::traceId() const
2127 {
2128     return String::empty();
2129 }
2130 
encodeFlags(const TokenDict * tokens) const2131 unsigned int String::encodeFlags(const TokenDict* tokens) const
2132 {
2133     unsigned int flags = 0;
2134     ObjList* list = split(',',false);
2135     for (ObjList* o = list->skipNull(); o; o = o->skipNext()) {
2136 	flags |= (unsigned int)(lookup(*static_cast<String*>(o->get()),tokens));
2137     }
2138     TelEngine::destruct(list);
2139     return flags;
2140 }
2141 
encodeFlags(const TokenDict64 * tokens) const2142 uint64_t String::encodeFlags(const TokenDict64* tokens) const
2143 {
2144     uint64_t flags = 0;
2145     ObjList* list = split(',',false);
2146     for (ObjList* o = list->skipNull(); o; o = o->skipNext()) {
2147 	flags |= (uint64_t)(lookup(*static_cast<String*>(o->get()),tokens));
2148     }
2149     TelEngine::destruct(list);
2150     return flags;
2151 }
2152 
decodeFlags(unsigned int flags,const TokenDict * tokens,bool unknownflag)2153 const String& String::decodeFlags(unsigned int flags, const TokenDict* tokens, bool unknownflag)
2154 {
2155     if (tokens) {
2156 	for(; tokens->token && flags; tokens++) {
2157 	    if ((tokens->value & flags) == (unsigned int)tokens->value) {
2158 		append(tokens->token,",");
2159 		flags &= ~tokens->value;
2160 	    }
2161 	}
2162     }
2163     if (flags && unknownflag)
2164 	append(String(flags),",");
2165     return *this;
2166 }
2167 
decodeFlags(uint64_t flags,const TokenDict64 * tokens,bool unknownflag)2168 const String& String::decodeFlags(uint64_t flags, const TokenDict64* tokens, bool unknownflag)
2169 {
2170     if (tokens) {
2171 	for (; tokens->token && flags; tokens++) {
2172 	    if ((tokens->value & flags) == (uint64_t)tokens->value ) {
2173 		append(tokens->token,",");
2174 		flags &= ~tokens->value;
2175 	    }
2176 	}
2177     }
2178     if (flags && unknownflag)
2179 	append(String(flags),",");
2180     return *this;
2181 }
2182 
2183 /* vi: set ts=8 sw=4 sts=4 noet: */
2184