libcsdbg  1.28
C++ exception (and generic) stack trace debug library
string.cpp
Go to the documentation of this file.
1 #include "../include/string.hpp"
2 #include "../include/util.hpp"
3 #if !defined CSDBG_WITH_PLUGIN && !defined CSDBG_WITH_HIGHLIGHT
4 #include "../include/exception.hpp"
5 #endif
6 
13 namespace csdbg {
14 
26 string& string::memalign(u32 len, bool keep)
27 {
28  if ( unlikely(len < m_size) )
29  return (keep) ? *this : clear();
30 
31  i8 *copy = NULL;
32  if ( unlikely(keep) ) {
33  __D_ASSERT(m_data != NULL);
34  __D_ASSERT(strlen(m_data) == m_length);
35 
36  copy = new i8[m_length + 1];
37  strcpy(copy, m_data);
38  }
39 
40  /* Aligned size */
43 
44  try {
45  delete[] m_data;
46  m_data = NULL;
47  m_data = new i8[m_size];
48  }
49 
50  catch (...) {
51  delete[] copy;
52  throw;
53  }
54 
55  if ( unlikely(keep) ) {
56  strcpy(m_data, copy);
57  delete[] copy;
58  return *this;
59  }
60 
61  return clear();
62 }
63 
64 
79 string& string::format(const i8 *fmt, va_list args)
80 {
81  __D_ASSERT(fmt != NULL);
82  if ( unlikely(fmt == NULL) ) {
83  va_end(args);
84  return memalign(0);
85  }
86 
87  try {
88  va_list cpargs;
89  va_copy(cpargs, args);
90  u32 len = util::va_size(fmt, cpargs);
91  memalign(len);
92 
93  util::va_format(m_data, fmt, args);
94  m_length = len;
95  return *this;
96  }
97 
98  catch (...) {
99  va_end(args);
100  throw;
101  }
102 }
103 
104 
114 std::ostream& operator<<(std::ostream &lval, const string &rval)
115 {
116  return lval << rval.m_data;
117 }
118 
119 
128 m_data(NULL),
129 m_length(0),
130 m_size(0)
131 {
132  memalign(sz);
133 }
134 
135 
150 string::string(const i8 *fmt, ...):
151 m_data(NULL),
152 m_length(0),
153 m_size(0)
154 {
155  __D_ASSERT(fmt != NULL);
156  if ( unlikely(fmt == NULL) )
157  memalign(0);
158 
159  else {
160  va_list args;
161  va_start(args, fmt);
162  format(fmt, args);
163  }
164 }
165 
166 
174 string::string(const string &src):
175 m_data(NULL),
176 m_length(0),
177 m_size(0)
178 {
179  *this = src;
180 }
181 
182 
187 {
188  delete[] m_data;
189  m_data = NULL;
190 }
191 
192 
200 inline string* string::clone() const
201 {
202  return new string(*this);
203 }
204 
205 
211 inline const i8* string::cstr() const
212 {
213  return m_data;
214 }
215 
216 
222 inline u32 string::length() const
223 {
224  return m_length;
225 }
226 
227 
233 inline u32 string::bufsize() const
234 {
235  return m_size;
236 }
237 
238 
248 inline i8& string::at(u32 i)
249 {
250  if ( unlikely(i >= m_length) )
251  throw exception("offset out of string bounds (%d >= %d)", i, m_length);
252 
253  return m_data[i];
254 }
255 
256 
271 string& string::set(const i8 *fmt, ...)
272 {
273  __D_ASSERT(fmt != NULL);
274  if ( unlikely(fmt == NULL) )
275  return memalign(0);
276 
277  __D_ASSERT(fmt != m_data);
278  if ( unlikely(fmt == m_data) )
279  return *this;
280 
281  va_list args;
282  va_start(args, fmt);
283  return format(fmt, args);
284 }
285 
286 
296 string& string::set(const string &src)
297 {
298  if ( unlikely(this == &src) )
299  return *this;
300 
301  memalign(src.m_length);
302  strcpy(m_data, src.m_data);
303  m_length = src.m_length;
304  return *this;
305 }
306 
307 
317 inline string& string::operator=(const string &rval)
318 {
319  return set(rval);
320 }
321 
322 
332 inline string& string::operator+=(const string &rval)
333 {
334  return append(rval);
335 }
336 
337 
348 {
349  return at(i);
350 }
351 
352 
360 inline u32 string::available() const
361 {
362  return m_size - m_length - 1;
363 }
364 
365 
375 inline string& string::shred(u8 ch)
376 {
377  util::memset(m_data, ch, m_size);
378  return clear();
379 }
380 
381 
387 inline string& string::clear()
388 {
389  m_data[0] = '\0';
390  m_length = 0;
391  return *this;
392 }
393 
394 
404 string& string::append(const string &tail)
405 {
406  u32 len = m_length + tail.m_length;
407  memalign(len, true);
408  strcpy(m_data + m_length, tail.m_data);
409  m_length = len;
410  return *this;
411 }
412 
413 
428 string& string::append(const i8 *fmt, ...)
429 {
430  __D_ASSERT(fmt != NULL);
431  if ( unlikely(fmt == NULL) )
432  return *this;
433 
434  string tmp;
435  va_list args;
436  va_start(args, fmt);
437  tmp.format(fmt, args);
438 
439  return append(tmp);
440 }
441 
442 
453 inline string& string::append(i8 ch)
454 {
455  return append("%c", ch);
456 }
457 
458 
470 inline i32 string::cmp(const string &rval, bool icase) const
471 {
472  if ( unlikely(icase) )
473  return strcasecmp(m_data, rval.m_data);
474 
475  return strcmp(m_data, rval.m_data);
476 }
477 
478 
490 bool string::match(const string &exp, bool icase) const
491 {
492  i32 flags = REG_EXTENDED | REG_NOSUB;
493  if ( unlikely(icase) )
494  flags |= REG_ICASE;
495 
496  /* Compile the regular expression and perform the matching */
497  regex_t regexp;
498  i32 retval = regcomp(&regexp, exp.cstr(), flags);
499  if ( likely(retval == 0) ) {
500  retval = regexec(&regexp, m_data, 0, NULL, 0);
501  regfree(&regexp);
502  return !retval;
503  }
504 
505  /* If the expression compilation failed */
506  i32 len = regerror(retval, &regexp, NULL, 0);
507  i8 errbuf[len];
508  regerror(retval, &regexp, errbuf, len);
509  regfree(&regexp);
510 
511  throw exception(
512  "failed to compile regexp '%s' (regex errno %d - %s)",
513  exp.cstr(),
514  retval,
515  errbuf
516  );
517 }
518 
519 
520 #if defined CSDBG_WITH_PLUGIN || defined CSDBG_WITH_HIGHLIGHT
521 
529 string& string::trim(i32 which)
530 {
531  if ( likely(which <= 0) ) {
532  /* Estimate the number of leading whitespace characters */
533  u32 i;
534  for (i = 0; likely(i < m_length); i++)
535  if ( likely(!isspace(m_data[i])) )
536  break;
537 
538  /* Remove them */
539  if ( unlikely(i > 0 && i < m_length) ) {
540  strcpy(m_data, m_data + i);
541  m_length -= i;
542  }
543 
544  /* If the string is filled with whitespace characters */
545  else if ( unlikely(i == m_length) )
546  return clear();
547  }
548 
549  if ( likely(which >= 0) ) {
550  /* Estimate the number of trailing whitespace characters */
551  i32 i;
552  for (i = m_length - 1; likely(i >= 0); i--)
553  if ( likely(!isspace(m_data[i])) )
554  break;
555 
556  m_data[++i] = '\0';
557  m_length = i;
558  }
559 
560  return *this;
561 }
562 
563 
575 string& string::insert(u32 pos, const string &rval)
576 {
577  if ( unlikely(pos >= m_length) )
578  return append(rval);
579 
580  u32 len = m_length + rval.m_length;
581  memalign(len, true);
582 
583  /* Shift the string to make place for the inserted text */
584  u32 i = m_length;
585  u32 j = len;
586  i32 tail = m_length - pos;
587  while ( likely(tail-- >= 0) )
588  m_data[j--] = m_data[i--];
589 
590  strncpy(m_data + pos, rval.m_data, rval.m_length);
591  m_length = len;
592  return *this;
593 }
594 
595 
612 string& string::insert(u32 pos, const i8 *fmt, ...)
613 {
614  __D_ASSERT(fmt != NULL);
615  if ( unlikely(fmt == NULL) )
616  return *this;
617 
618  /* Format a temporary string */
619  string tmp;
620  va_list args;
621  va_start(args, fmt);
622  tmp.format(fmt, args);
623 
624  return insert(pos, tmp);
625 }
626 
627 
642 chain<string>* string::split(const string &exp, bool imatch, bool icase) const
643 {
644  chain<string> *tokens = NULL;
645  string *word = NULL;
646  regex_t regexp;
647 
648  /* If an exception occurs, release resources and rethrow it */
649  try {
650  tokens = new chain<string>;
651 
652  /* Compile the regular expression */
653  i32 flags = REG_EXTENDED;
654  if ( unlikely(icase) )
655  flags |= REG_ICASE;
656 
657  i32 retval = regcomp(&regexp, exp.cstr(), flags);
658  if ( unlikely(retval != 0) ) {
659  i32 len = regerror(retval, &regexp, NULL, 0);
660  i8 errbuf[len];
661  regerror(retval, &regexp, errbuf, len);
662 
663  throw exception(
664  "failed to compile regexp '%s' (regex errno %d - %s)",
665  exp.cstr(),
666  retval,
667  errbuf
668  );
669  }
670 
671  regmatch_t match;
672  regoff_t offset = 0;
673  i32 len = m_length;
674  do {
675  bool found = !regexec(&regexp, m_data + offset, 1, &match, 0);
676 
677  /*
678  * The delimiter pattern is found. The left token is from the beginning of
679  * the text plus an offset, to the beginning of the matched text. The
680  * right token is from the end of the matched text to the end of the text
681  * or to the beginning of the next matched text. This will be evaluated on
682  * the next loop pass
683  */
684  if ( likely(found) ) {
685  i32 bgn = match.rm_so;
686  i32 end = match.rm_eo;
687  if ( unlikely(end == 0) )
688  throw exception("logic error in regular expression '%s'", exp.cstr());
689 
690  word = new string("%.*s", bgn, m_data + offset);
691  tokens->add(word);
692  word = NULL;
693 
694  if ( unlikely(!imatch) ) {
695  word = new string("%.*s", end - bgn, m_data + offset + bgn);
696  tokens->add(word);
697  word = NULL;
698  }
699 
700  offset += end;
701  if ( unlikely(offset > len) )
702  break;
703  }
704 
705  /*
706  * The pattern isn't found. That means that either the delimiter was never
707  * in the text, so the whole text is the one and only token, or there is
708  * some text after the last delimiter. In that case this trailing text is
709  * the last token
710  */
711  else if ( likely(offset <= len) ) {
712  word = new string(m_data + offset);
713  tokens->add(word);
714  word = NULL;
715  break;
716  }
717 
718  /* No more tokens */
719  else
720  break;
721  }
722 
723  while ( likely(true) );
724 
725  regfree(&regexp);
726  return tokens;
727  }
728 
729  catch (...) {
730  delete tokens;
731  delete word;
732  regfree(&regexp);
733  throw;
734  }
735 }
736 #endif
737 
738 }
739 
virtual string & trim(i32=0)
Remove leading and/or trailing whitespace characters.
Definition: string.cpp:529
virtual string & append(const string &)
Append a string.
Definition: string.cpp:404
virtual string * clone() const
Object virtual copy constructor.
Definition: string.cpp:200
virtual string & set(const i8 *,...)
Fill with a printf-style format C-string expanded with the values of a variable argument list...
Definition: string.cpp:271
virtual u32 available() const
Get the available buffer size, the number of characters that can be appended without reallocation...
Definition: string.cpp:360
virtual u32 bufsize() const
Get the buffer size.
Definition: string.cpp:233
virtual string & operator+=(const string &)
Compound addition-assignment operator (append)
Definition: string.cpp:332
virtual string & format(const i8 *, va_list)
Fill with a printf-style format C-string expanded with the values of a variable argument list...
Definition: string.cpp:79
static void * memset(void *, u8, u32)
Fill a memory block with a constant byte.
Definition: util.cpp:320
char i8
8-bit signed integer
Definition: config.hpp:72
std::ostream & operator<<(std::ostream &, const std::exception &)
Stream insertion operator for std::exception objects.
Definition: exception.cpp:23
virtual ~string()
Object destructor.
Definition: string.cpp:186
static const u16 g_memblock_sz
Block size (allocation alignment)
Definition: config.hpp:202
virtual string & operator=(const string &)
Assignment operator.
Definition: string.cpp:317
virtual string & insert(u32, const string &)
Insert a string at a specified position.
Definition: string.cpp:575
string(u32=0)
Object constructor.
Definition: string.cpp:127
#define likely(expr)
Offer a hint (positive) to the pipeline branch predictor.
Definition: config.hpp:344
virtual string & memalign(u32, bool=false)
Allocate aligned memory, mandate a minimum buffer size.
Definition: string.cpp:26
virtual i8 & operator[](u32)
Subscript operator.
Definition: string.cpp:347
unsigned char u8
8-bit unsigned integer
Definition: config.hpp:92
virtual string & clear()
Clear contents.
Definition: string.cpp:387
virtual i32 cmp(const string &, bool=false) const
Compare to another string.
Definition: string.cpp:470
virtual i8 & at(u32)
Get/set the character at an offset.
Definition: string.cpp:248
virtual const i8 * cstr() const
Get the C-string equivalent.
Definition: string.cpp:211
virtual chain & add(T *)
Add a node to the chain.
Definition: chain.hpp:363
virtual bool match(const string &, bool=false) const
Match against a POSIX extended regular expression.
Definition: string.cpp:490
u32 m_size
Buffer size.
Definition: string.hpp:46
i8 * m_data
String data.
Definition: string.hpp:42
static i8 * va_format(const i8 *, va_list)
Format a buffer with a printf-style string expanded with the values of a variable argument list...
Definition: util.cpp:519
unsigned int u32
32-bit unsigned integer
Definition: config.hpp:102
int i32
32-bit signed integer
Definition: config.hpp:82
virtual u32 length() const
Get the character count.
Definition: string.cpp:222
virtual string & shred(u8=0)
Fill the whole buffer with a constant byte.
Definition: string.cpp:375
This class is a throwable with a textual description of an error.
Definition: exception.hpp:26
virtual chain< string > * split(const string &, bool=true, bool=false) const
Tokenize using a POSIX extended regular expression.
Definition: string.cpp:642
static i32 va_size(const i8 *, va_list)
Compute the size of a printf-style format string expanded with the values of a variable argument list...
Definition: util.cpp:489
#define unlikely(expr)
Offer a hint (negative) to the pipeline branch predictor.
Definition: config.hpp:349
u32 m_length
Character count.
Definition: string.hpp:44
#define __D_ASSERT(x)
Assertion macro.
Definition: config.hpp:268