--- parser3/src/main/pa_string.C 2003/12/10 14:17:45 1.192 +++ parser3/src/main/pa_string.C 2004/02/27 15:24:03 1.196 @@ -1,11 +1,11 @@ /** @file Parser: string class. @see untalength_t.C. - Copyright (c) 2001-2003 ArtLebedev Group (http://www.artlebedev.com) + Copyright (c) 2001-2004 ArtLebedev Group (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) */ -static const char * const IDENT_STRING_C="$Date: 2003/12/10 14:17:45 $"; +static const char * const IDENT_STRING_C="$Date: 2004/02/27 15:24:03 $"; #include "pcre.h" @@ -17,6 +17,64 @@ static const char * const IDENT_STRING_C const String String::Empty; +int pa_atoi(const char* str, const String* problem_source) { + if(!str) + return 0; + + while(*str && isspace(*str)) + str++; + if(!*str) + return 0; + + int result; + char *error_pos; + // 0xABC + if(str[0]=='0') + if(str[1]=='x' || str[1]=='X') + result=(int)(unsigned long)strtol(str, &error_pos, 0); + else + result=(int)strtol(str+1/*skip leading 0*/, &error_pos, 0); + else + result=(int)strtol(str, &error_pos, 0); + + while(char c=*error_pos++) + if(!isspace(c)) + throw Exception("number.format", + problem_source, + problem_source?"invalid number (int)": "'%s' is invalid number (int)", str); + + return result; +} + +double pa_atod(const char* str, const String* problem_source) { + if(!str) + return 0; + + while(*str && isspace(*str)) + str++; + if(!*str) + return 0; + + double result; + char *error_pos; + // 0xABC + if(str[0]=='0') + if(str[1]=='x' || str[1]=='X') + result=(double)(unsigned long)strtol(str, &error_pos, 0); + else + result=(double)strtod(str+1/*skip leading 0*/, &error_pos); + else + result=(double)strtod(str, &error_pos); + + while(char c=*error_pos++) + if(!isspace(c)) + throw Exception("number.format", + problem_source, + problem_source?"invalid number (double)": "'%s' is invalid number (double)", str); + + return result; +} + // cord lib extension #ifndef DOXYGEN @@ -84,6 +142,58 @@ String::Body String::Body::Format(int va return String::Body(pa_strdup(local, length), length); } +String::Body String::Body::trim(String::Trim_kind kind, const char* chars, + size_t* out_start, size_t* out_length) const { + size_t our_length=length(); + if(!our_length) + return *this; + if(!chars) + chars=" \t\n"; // white space + Body result=*this; + + size_t start=0; + size_t end=our_length; + // from left... + if(kind!=TRIM_END) { + CORD_pos pos; set_pos(pos, 0); + while(true) { + char c=CORD_pos_fetch(pos); + if(strchr(chars, c)) { + if(++start==our_length) + return 0; // all chars are empty, just return empty string + } else + break; + + CORD_next(pos); + } + } + // from right.. + if(kind!=TRIM_START) { + CORD_pos pos; set_pos(pos, end-1); + while(true) { + char c=CORD_pos_fetch(pos); + if(strchr(chars, c)) { + if(--end==0) // optimization: NO need to check for 'end>=start', that's(<) impossible + return 0; // all chars are empty, just return empty string + } else + break; + + CORD_prev(pos); + } + } + + if(start==0 && end==our_length) // nobody moved a thing + return *this; + + if(out_start) + *out_start=start; + size_t new_length=end-start; + if(out_length) + *out_length=new_length; + + return mid(start, new_length); +} + static int CORD_batched_iter_fn_generic_hash_code(char c, void * client_data) { uint& result=*static_cast(client_data); generic_hash_code(result, c); @@ -459,61 +569,6 @@ const String& String::replace(const Dict return result; } -double String::as_double() const { - double result; - const char *str=cstr(); - - while(*str && isspace(*str)) - str++; - if(!*str) - return 0; - - char *error_pos; - // 0xABC - if(str[0]=='0') - if(str[1]=='x' || str[1]=='X') - result=(double)(unsigned long)strtol(str, &error_pos, 0); - else - result=(double)strtod(str+1/*skip leading 0*/, &error_pos); - else - result=(double)strtod(str, &error_pos); - - while(char c=*error_pos++) - if(!isspace(c)) - throw Exception("number.format", - this, - "invalid number (double)"); - - return result; -} -int String::as_int() const { - int result; - const char *str=cstr(); - - while(*str && isspace(*str)) - str++; - if(!*str) - return 0; - - char *error_pos; - // 0xABC - if(str[0]=='0') - if(str[1]=='x' || str[1]=='X') - result=(int)(unsigned long)strtol(str, &error_pos, 0); - else - result=(int)strtol(str+1/*skip leading 0*/, &error_pos, 0); - else - result=(int)strtol(str, &error_pos, 0); - - while(char c=*error_pos++) - if(!isspace(c)) - throw Exception("number.format", - this, - "invalid number (int)"); - - return result; -} - static int serialize_body_char(char c, char** cur) { *((*cur)++)=c; return 0; // 0=continue @@ -615,7 +670,7 @@ const char* String::Languages::v() const return (const char*)&langs; } const char* String::v() const { -#define LIMIT_VIEW 20 + const int LIMIT_VIEW=20; char* buf=(char*)malloc(MAX_STRING); const char*body_view=body.v(); const char*langs_view=langs.v(); @@ -627,5 +682,28 @@ const char* String::v() const { ); return buf; -#undef LIMIT_VIEW } + +const String& String::trim(String::Trim_kind kind, const char* chars) const { + if(!length()) + return *this; + + size_t substr_begin, substr_length; + Body new_body=body.trim(kind, chars, &substr_begin, &substr_length); + if(new_body==body) // we received unchanged pointer, do likewise + return *this; + // new_body differs from body, adjust langs along + + String& result=*new String; + if(!new_body) // body.trim produced empty result + return result; + // body.trim produced nonempty result + + // first: their langs + result.langs.append(result.body, langs, substr_begin, substr_length); + // next: letters themselves + result.body=new_body; + + ASSERT_STRING_INVARIANT(result); + return result; +} \ No newline at end of file