Diff for /parser3/src/main/pa_string.C between versions 1.238 and 1.254

version 1.238, 2012/01/08 05:58:27 version 1.254, 2016/09/05 21:59:22
Line 1 Line 1
 /** @file  /** @file
         Parser: string class. @see untalength_t.C.          Parser: string class. @see untalength_t.C.
   
         Copyright (c) 2001-2009 ArtLebedev Group (http://www.artlebedev.com)          Copyright (c) 2001-2015 Art. Lebedev Studio (http://www.artlebedev.com)
         Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)          Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
 */  */
   
 static const char * const IDENT_STRING_C="$Date$";  
   
 #include "pa_string.h"  #include "pa_string.h"
 #include "pa_exception.h"  #include "pa_exception.h"
 #include "pa_table.h"  #include "pa_table.h"
Line 14  static const char * const IDENT_STRING_C Line 12  static const char * const IDENT_STRING_C
 #include "pa_charset.h"  #include "pa_charset.h"
 #include "pa_vregex.h"  #include "pa_vregex.h"
   
   #ifndef ULLONG_MAX
   #define ULLONG_MAX 18446744073709551615ULL
   #endif
   
   volatile const char * IDENT_PA_STRING_C="$Id$" IDENT_PA_STRING_H;
   
 const String String::Empty;  const String String::Empty;
   
   // pa_atoui is based on Manuel Novoa III _strto_l for uClibc
   
   template<typename T> inline T pa_ato_any(const char *str, int base, const String* problem_source,const T max){
           T result = 0;
           const char *pos = str;
   
           while (isspace(*pos)) /* skip leading whitespace */
                   ++pos;
   
           if (base == 16 && *pos == '0') { /* handle option prefix */
                   ++pos;
                   if (*pos == 'x' || *pos == 'X') {
                           ++pos;
                   }
           }
   
           if (base == 0) { /* dynamic base */
                   base = 10; /* default is 10 */
                   if (*pos == '0') {
                           ++pos;
                           if (*pos == 'x' || *pos == 'X'){
                                   ++pos;
                                   base=16;
                           }
                   }
           }
   
           if (base < 2 || base > 16) { /* illegal base */
                   throw Exception(PARSER_RUNTIME, 0, "base to must be an integer from 2 to 16");
           }
   
           T cutoff = max / base;
           int cutoff_digit = (int)(max - cutoff * base);
   
           while(true) {
                   int digit;
                   
                   if ((*pos >= '0') && (*pos <= '9')) {
                           digit = (*pos - '0');
                   } else if (*pos >= 'a') {
                           digit = (*pos - 'a' + 10);
                   } else if (*pos >= 'A') {
                           digit = (*pos - 'A' + 10);
                   } else break;
   
                   if (digit >= base) {
                           break;
                   }
                   
                   ++pos;
                   
                   /* adjust number, with overflow check */
                   if ((result > cutoff) || ((result == cutoff) && (digit > cutoff_digit))) {
                           throw Exception("number.format", problem_source, problem_source ? "out of range (int)" : "'%s' is out of range (int)", str);
                   } else {
                           result  = result * base + digit;
                   }
           }
   
           while(char c=*pos++)
                   if(!isspace(c))
                           throw Exception("number.format", problem_source, problem_source ? "invalid number (int)" : "'%s' is invalid number (int)", str);
   
           return result;
   }
   
   unsigned int pa_atoui(const char *str, int base, const String* problem_source){
           return pa_ato_any<unsigned int>(str, base, problem_source, UINT_MAX);
   }
   
   unsigned long long pa_atoul(const char *str, int base, const String* problem_source){
           return pa_ato_any<unsigned long long int>(str, base, problem_source, ULLONG_MAX);
   }
   
 int pa_atoi(const char* str, const String* problem_source) {  int pa_atoi(const char* str, const String* problem_source) {
         if(!str)          if(!str)
                 return 0;                  return 0;
   
         while(*str && isspace((unsigned char)*str))          while(isspace(*str))
                 str++;                  str++;
   
         if(!*str)          if(!*str)
                 return 0;                  return 0;
   
         int result;  
         char *error_pos;  
         bool negative=false;          bool negative=false;
         if(str[0]=='-') {          if(str[0]=='-') {
                 negative=true;                  negative=true;
Line 34  int pa_atoi(const char* str, const Strin Line 111  int pa_atoi(const char* str, const Strin
         } else if(str[0]=='+') {          } else if(str[0]=='+') {
                 str++;                  str++;
         }          }
         // 0xABC  
         if(str[0]=='0')  
                 if(str[1]=='x' || str[1]=='X')  
                         result=(int)(unsigned long)strtol(str, &error_pos, 0);  
                 else {  
                          // skip leading 0000, to disable octal interpretation  
                         do str++; while(*str=='0');                               
                         result=(int)strtol(str, &error_pos, 0);  
                 }  
         else  
                 result=(int)strtol(str, &error_pos, 0);  
         if(negative)  
                 result=-result;  
   
         while(char c=*error_pos++)          unsigned int result=pa_atoui(str, 0, problem_source);
                 if(!isspace((unsigned char)c))  
                         throw Exception("number.format",  
                                 problem_source,  
                                 problem_source?"invalid number (int)": "'%s' is invalid number (int)", str);  
   
         return result;          if(negative && result <= ((unsigned int)(-(1+INT_MIN)))+1)
                   return -(int)result;
           
           if(result<=INT_MAX)
                   return (int)result;
           
           throw Exception("number.format", problem_source, problem_source ? "out of range (int)" : "'%s' is out of range (int)", str);
 }  }
   
 double pa_atod(const char* str, const String* problem_source) {  double pa_atod(const char* str, const String* problem_source) {
         if(!str)          if(!str)
                 return 0;                  return 0;
   
         while(*str && isspace((unsigned char)*str))          while(isspace(*str))
                 str++;                  str++;
   
         if(!*str)          if(!*str)
                 return 0;                  return 0;
   
         double result;  
         char *error_pos;  
         bool negative=false;          bool negative=false;
         if(str[0]=='-') {          if(str[0]=='-') {
                 negative=true;                  negative=true;
Line 75  double pa_atod(const char* str, const St Line 140  double pa_atod(const char* str, const St
         } else if(str[0]=='+') {          } else if(str[0]=='+') {
                 str++;                  str++;
         }          }
         // 0xABC  
         if(str[0]=='0')          double result;
                 if(str[1]=='x' || str[1]=='X')          if(str[0]=='0') {
                         result=(double)(unsigned long)strtol(str, &error_pos, 0);                  if(str[1]=='x' || str[1]=='X') {
                 else {                          // 0xABC
                           result=(double)pa_atoul(str, 0, problem_source);
                           return negative ? -result : result;
                   } else {
                          // skip leading 0000, to disable octal interpretation                           // skip leading 0000, to disable octal interpretation
                         do str++; while(*str=='0');                                                       do str++; while(*str=='0');
                         result=(double)strtod(str, &error_pos);  
                 }                  }
         else          }
                 result=(double)strtod(str, &error_pos);  
         if(negative)          char *error_pos;
                 result=-result;          result=strtod(str, &error_pos);
   
         while(char c=*error_pos++)          while(char c=*error_pos++)
                 if(!isspace((unsigned char)c))                  if(!isspace((unsigned char)c))
                         throw Exception("number.format",                          throw Exception("number.format", problem_source, problem_source ? "invalid number (double)" : "'%s' is invalid number (double)", str);
                                 problem_source,  
                                 problem_source?"invalid number (double)": "'%s' is invalid number (double)", str);  
   
         return result;          return negative ? -result : result;
 }  }
   
 // cord lib extension  // cord lib extension
   
 #ifndef DOXYGEN  #ifndef DOXYGEN
 typedef struct {  typedef struct {
     ssize_t countdown;          ssize_t countdown;
     int target; /* Character we're looking for  */          int target;     /* Character we're looking for  */
 } chr_data;  } chr_data;
 #endif  #endif
   
 static int CORD_range_contains_chr_greater_then_proc(char c, size_t size, void* client_data)  static int CORD_range_contains_chr_greater_then_proc(char c, size_t size, void* client_data)
 {  {
     register chr_data * d = (chr_data *)client_data;          register chr_data * d = (chr_data *)client_data;
       
     if (d -> countdown<=0) return(2);          if (d -> countdown<=0) return(2);
     d -> countdown -= size;          d -> countdown -= size;
     if (c > d -> target) return(1);          if (c > d -> target) return(1);
     return(0);          return(0);
 }  }
   
 int CORD_range_contains_chr_greater_then(CORD x, size_t i, size_t n, int c)  int CORD_range_contains_chr_greater_then(CORD x, size_t i, size_t n, int c)
 {  {
     chr_data d;          chr_data d;
   
     d.countdown = n;          d.countdown = n;
     d.target = c;          d.target = c;
     return(CORD_block_iter(x, i, CORD_range_contains_chr_greater_then_proc, &d) == 1/*alternatives: 0 normally ended, 2=struck 'n'*/);          return(CORD_block_iter(x, i, CORD_range_contains_chr_greater_then_proc, &d) == 1/*alternatives: 0 normally ended, 2=struck 'n'*/);
 }  }
   
 static int CORD_block_count_proc(char /*c*/, size_t /*size*/, void* client_data)  static int CORD_block_count_proc(char /*c*/, size_t /*size*/, void* client_data)
 {  {
     int* result=(int*)client_data;          int* result=(int*)client_data;
     (*result)++;          (*result)++;
     return(0); // 0=continue          return(0); // 0=continue
 }  }
   
 size_t CORD_block_count(CORD x)  size_t CORD_block_count(CORD x)
 {  {
         size_t result=0;          size_t result=0;
         CORD_block_iter(x, 0, CORD_block_count_proc, &result);          CORD_block_iter(x, 0, CORD_block_count_proc, &result);
     return result;          return result;
 }  }
   
 // helpers  // helpers
Line 165  String::Body String::Body::Format(int va Line 233  String::Body String::Body::Format(int va
         return String::Body(pa_strdup(local, length));          return String::Body(pa_strdup(local, length));
 }  }
   
 String::Body String::Body::trim(String::Trim_kind kind, const char* chars,   String::Body String::Body::trim(String::Trim_kind kind, const char* chars, size_t* out_start, size_t* out_length, Charset* source_charset) const {
                                                                 size_t* out_start, size_t* out_length, Charset* source_charset) const {  
         size_t our_length=length();          size_t our_length=length();
         if(!our_length)          if(!our_length)
                 return *this;                  return *this;
Line 288  static int CORD_batched_iter_fn_generic_ Line 355  static int CORD_batched_iter_fn_generic_
         generic_hash_code(result, c);          generic_hash_code(result, c);
         return 0;          return 0;
 }  }
   
 static int CORD_batched_iter_fn_generic_hash_code(const char*  s, void * client_data) {  static int CORD_batched_iter_fn_generic_hash_code(const char*  s, void * client_data) {
         uint& result=*static_cast<uint*>(client_data);          uint& result=*static_cast<uint*>(client_data);
         generic_hash_code(result, s);          generic_hash_code(result, s);
         return 0;          return 0;
 };  }
   
 uint String::Body::get_hash_code() const {  uint String::Body::get_hash_code() const {
 #ifdef HASH_CODE_CACHING  #ifdef HASH_CODE_CACHING
         if(hash_code)          if(hash_code)
Line 301  uint String::Body::get_hash_code() const Line 370  uint String::Body::get_hash_code() const
         uint hash_code=0;          uint hash_code=0;
 #endif  #endif
         if (body && CORD_IS_STRING(body)){          if (body && CORD_IS_STRING(body)){
                 generic_hash_code(hash_code, body);                  generic_hash_code(hash_code, (const char *)body);
         } else {          } else {
                 CORD_iter5(body, 0,                  CORD_iter5(body, 0,
                         CORD_batched_iter_fn_generic_hash_code,                           CORD_batched_iter_fn_generic_hash_code, 
Line 310  uint String::Body::get_hash_code() const Line 379  uint String::Body::get_hash_code() const
         return hash_code;          return hash_code;
 }  }
   
   struct CORD_pos_info {
           const char* chars;
           size_t left;
           size_t pos;
   };
   
   // can be called only for IS_FUNCTION(CORD) which is used in String::Body::strrpbrk
   static int CORD_iter_fn_rpos(char c, CORD_pos_info* info) {
           if(info->pos < info->left){
                   info->pos=STRING_NOT_FOUND;
                   return 1;
           }
           if(strchr(info->chars, c))
                   return 1;
           --(info->pos);
           return 0;
   }
   
   size_t String::Body::strrpbrk(const char* chars, size_t left, size_t right) const {
           if(is_empty() || !chars || !strlen(chars))
                   return STRING_NOT_FOUND;
           CORD_pos_info info={chars, left, right};
           if(CORD_riter4(body, right, (CORD_iter_fn)CORD_iter_fn_rpos, &info))
                   return info.pos;
           else
                   return STRING_NOT_FOUND;
   }
   
   
   // can be called only for IS_FUNCTION(CORD) which is used in String::Body::rskipchars
   static int CORD_iter_fn_rskip(char c, CORD_pos_info* info) {
           if(info->pos < info->left) {
                   info->pos=STRING_NOT_FOUND;
                   return 1;
           }
           if(!strchr(info->chars, c))
                   return 1;
           --(info->pos);
           return 0;
   }
   
   size_t String::Body::rskipchars(const char* chars, size_t left, size_t right) const {
           if(is_empty() || !chars || !strlen(chars))
                   return STRING_NOT_FOUND;
           CORD_pos_info info={chars, left, right};
           if(CORD_riter4(body, right, (CORD_iter_fn)CORD_iter_fn_rskip, &info))
                   return info.pos;
           else
                   return STRING_NOT_FOUND;
   }
   
 // String methods  // String methods
   
 String& String::append_know_length(const char* str, size_t known_length, Language lang) {  String& String::append_know_length(const char* str, size_t known_length, Language lang) {
Line 324  String& String::append_know_length(const Line 444  String& String::append_know_length(const
         ASSERT_STRING_INVARIANT(*this);          ASSERT_STRING_INVARIANT(*this);
         return *this;          return *this;
 }  }
   
 String& String::append_help_length(const char* str, size_t helper_length, Language lang) {  String& String::append_help_length(const char* str, size_t helper_length, Language lang) {
         if(!str)          if(!str)
                 return *this;                  return *this;
Line 333  String& String::append_help_length(const Line 454  String& String::append_help_length(const
   
         return append_know_length(str, known_length, lang);          return append_know_length(str, known_length, lang);
 }  }
 String::String(int value, char *format) : langs(L_CLEAN){  
   String::String(int value, const char *format) : langs(L_CLEAN){
         char buf[MAX_NUMBER];          char buf[MAX_NUMBER];
         body.append_strdup_know_length(buf, snprintf(buf, MAX_NUMBER, format, value));          body.append_strdup_know_length(buf, snprintf(buf, MAX_NUMBER, format, value));
 }  }
   
 String& String::append_strdup(const char* str, size_t helper_length, Language lang) {  String& String::append_strdup(const char* str, size_t helper_length, Language lang) {
         size_t known_length=helper_length?helper_length:strlen(str);          size_t known_length=helper_length?helper_length:strlen(str);
         if(!known_length)          if(!known_length)
Line 452  size_t String::pos(const String::Body su Line 575  size_t String::pos(const String::Body su
         }          }
 }  }
   
 size_t String::pos(const String& substr,   size_t String::pos(const String& substr, size_t this_offset, Language lang) const {
                                 size_t this_offset, Language lang) const {  
         return pos(substr.body, this_offset, lang);          return pos(substr.body, this_offset, lang);
 }  }
   
 size_t String::pos(Charset& charset, const String& substr,   size_t String::pos(Charset& charset, const String& substr, size_t this_offset, Language lang) const {
                                 size_t this_offset, Language lang) const {  
   
         if(charset.isUTF8()){          if(charset.isUTF8()){
                 const XMLByte* srcPtr=(const XMLByte*)cstr();                  const XMLByte* srcPtr=(const XMLByte*)cstr();
Line 479  size_t String::pos(Charset& charset, con Line 600  size_t String::pos(Charset& charset, con
         }          }
 }  }
   
 void String::split(ArrayString& result,   void String::split(ArrayString& result, size_t& pos_after, const char* delim, Language lang, int limit) const {
                    size_t& pos_after,   
                    const char* delim,   
                    Language lang, int limit) const {  
         if(is_empty())          if(is_empty())
                 return;                  return;
         size_t self_length=length();          size_t self_length=length();
Line 504  void String::split(ArrayString& result, Line 622  void String::split(ArrayString& result,
         }          }
 }  }
   
 void String::split(ArrayString& result,   void String::split(ArrayString& result, size_t& pos_after, const String& delim, Language lang, int limit) const {
                    size_t& pos_after,   
                    const String& delim, Language lang,   
                    int limit) const {  
         if(is_empty())          if(is_empty())
                 return;                  return;
         if(!delim.is_empty()) {          if(!delim.is_empty()) {
Line 528  void String::split(ArrayString& result, Line 643  void String::split(ArrayString& result,
         }          }
 }  }
   
 Table* String::match(VRegex* vregex,  Table* String::match(VRegex* vregex, Row_action row_action, void *info, int& matches_count) const {
                         Row_action row_action, void *info,  
                         int& matches_count) const {   
   
         // vregex->info(); // I have no idea what does it for?          // vregex->info(); // I have no idea what does it for?
   
Line 671  const String& String::replace(const Dict Line 784  const String& String::replace(const Dict
                 // optimized simple case                  // optimized simple case
   
                 Dictionary::Subst subst=dict.get(0);                  Dictionary::Subst subst=dict.get(0);
                 while(char* p=strstr(prematch_begin, subst.from)) {                  while(const char* p=strstr(prematch_begin, subst.from)) {
                         // prematch                          // prematch
                         if(size_t prematch_length=p-prematch_begin) {                          if(size_t prematch_length=p-prematch_begin) {
                                 STRING_APPEND(result, prematch_begin, langs, prematch_begin-old_cstr, prematch_length)                                  STRING_APPEND(result, prematch_begin, langs, prematch_begin-old_cstr, prematch_length)
Line 721  const String& String::replace(const Dict Line 834  const String& String::replace(const Dict
 static int serialize_body_char(char c, char** cur) {  static int serialize_body_char(char c, char** cur) {
         *((*cur)++)=c;          *((*cur)++)=c;
         return 0; // 0=continue          return 0; // 0=continue
 };  }
   
 static int serialize_body_piece(const char* s, char** cur) {  static int serialize_body_piece(const char* s, char** cur) {
         size_t length=strlen(s);          size_t length=strlen(s);
         memcpy(*cur, s, length);  *cur+=length;          memcpy(*cur, s, length);  *cur+=length;
         return 0; // 0=continue          return 0; // 0=continue
 };  }
   
 static int serialize_lang_piece(char alang, size_t asize, char** cur) {  static int serialize_lang_piece(char alang, size_t asize, char** cur) {
         // lang          // lang
         **cur=alang; (*cur)++;          **cur=alang; (*cur)++;
Line 735  static int serialize_lang_piece(char ala Line 850  static int serialize_lang_piece(char ala
   
         return 0; // 0=continue          return 0; // 0=continue
 }  }
   
 String::Cm String::serialize(size_t prolog_length) const {  String::Cm String::serialize(size_t prolog_length) const {
         size_t fragments_count=langs.count();          size_t fragments_count=langs.count();
         size_t body_length=body.length();          size_t body_length=body.length();
Line 763  String::Cm String::serialize(size_t prol Line 879  String::Cm String::serialize(size_t prol
   
         return result;          return result;
 }  }
   
 bool String::deserialize(size_t prolog_size, void *buf, size_t buf_size) {  bool String::deserialize(size_t prolog_size, void *buf, size_t buf_size) {
         size_t in_buf=buf_size;          size_t in_buf=buf_size;
         if(in_buf<=prolog_size)          if(in_buf<=prolog_size)
Line 786  bool String::deserialize(size_t prolog_s Line 903  bool String::deserialize(size_t prolog_s
         if(cur[body_length] != 0) // in place?          if(cur[body_length] != 0) // in place?
                 return false;                  return false;
         // 3: letters          // 3: letters
         body=String::Body(*cur?cur:0);          body=String::Body(String::C(cur, body_length));
 #ifdef STRING_LENGTH_CACHING  
         body.set_length(body_length);  
 #endif  
         cur+=body_length+1;          cur+=body_length+1;
         in_buf-=body_length+1;          in_buf-=body_length+1;
   
Line 838  bool String::deserialize(size_t prolog_s Line 952  bool String::deserialize(size_t prolog_s
 const char* String::Body::v() const {  const char* String::Body::v() const {
         return CORD_to_const_char_star(body, length());          return CORD_to_const_char_star(body, length());
 }  }
   
 void String::Body::dump() const {  void String::Body::dump() const {
         CORD_dump(body);          CORD_dump(body);
 }  }
Line 848  const char* String::Languages::v() const Line 963  const char* String::Languages::v() const
         else          else
                 return (const char*)&langs;                  return (const char*)&langs;
 }  }
   
 void String::Languages::dump() const {  void String::Languages::dump() const {
         if(opt.is_not_just_lang)          if(opt.is_not_just_lang)
                 CORD_dump(langs);                  CORD_dump(langs);
         else          else
                 puts((const char*)&langs);                  puts((const char*)&langs);
 }  }
   
 const char* String::v() const {  const char* String::v() const {
         const uint LIMIT_VIEW=20;          const uint LIMIT_VIEW=20;
         char* buf=(char*)malloc(MAX_STRING);          char* buf=(char*)pa_malloc(MAX_STRING);
         const char*body_view=body.v();          const char*body_view=body.v();
         const char*langs_view=langs.v();          const char*langs_view=langs.v();
         snprintf(buf, MAX_STRING,           snprintf(buf, MAX_STRING, 

Removed from v.1.238  
changed lines
  Added in v.1.254


E-mail: