|
|
| version 1.174.2.1, 2003/07/28 07:36:39 | version 1.175.2.3, 2003/09/24 07:13:52 |
|---|---|
| Line 15 static const char* IDENT_STRING_C="$Date | Line 15 static const char* IDENT_STRING_C="$Date |
| #include "pa_dictionary.h" | #include "pa_dictionary.h" |
| #include "pa_charset.h" | #include "pa_charset.h" |
| // cord lib extension | |
| #ifndef DOXYGEN | |
| typedef struct { | |
| ssize_t countdown; | |
| char target; /* Character we're looking for */ | |
| } chr_data; | |
| #endif | |
| 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; | |
| if (d -> countdown<=0) return(2); | |
| d -> countdown -= size; | |
| if (c > d -> target) return(1); | |
| return(0); | |
| } | |
| int CORD_range_contains_chr_greater_then(CORD x, size_t i, size_t n, int not_c) | |
| { | |
| chr_data d; | |
| d.countdown = i+n; | |
| d.target = not_c; | |
| return(CORD_block_iter(x, i, CORD_range_contains_chr_greater_then_proc, &d) == 1/*alternatives: 0 normally ended, 2=struck 'n'*/); | |
| } | |
| // helpers | // helpers |
| /// String::match uses this as replace & global search table columns | /// String::match uses this as replace & global search table columns |
| Line 35 public: | Line 61 public: |
| Table string_match_table_template(new String_match_table_template_columns); | Table string_match_table_template(new String_match_table_template_columns); |
| // String::ArrayFragment methods | |
| void String::ArrayFragment::append_positions(const ArrayFragment& src, | |
| size_t substr_begin, size_t substr_end) { | |
| if(substr_begin==substr_end) | |
| return; | |
| // FILE *err=fopen("append.log", "wt"); | |
| size_t fragment_begin=0; | |
| size_t fragment_end; | |
| for(Array_iterator<element_type> i(src); ; fragment_begin=fragment_end) { | |
| const Fragment fragment=i.next(); | |
| fragment_end=fragment_begin+fragment.length; | |
| //fprintf(err, "1end=%u\n", fragment_end);fflush(err); | |
| // not reached fragments which may include 'substr'? | |
| if(!(substr_begin>=fragment_begin && substr_begin<fragment_end)) | |
| continue; | |
| // found first fragment including piece of 'substr' | |
| if(substr_end<=fragment_end) // fits into first fragment? | |
| *this+=Fragment(fragment.lang, substr_end-substr_begin); | |
| else { // spans more then one fragment | |
| *this+=Fragment(fragment.lang, fragment_end-substr_begin); | |
| while(true) { | |
| const Fragment fragment=i.next(); | |
| fragment_end=(fragment_begin=fragment_end)+fragment.length; | |
| //fprintf(err, "2end=%u\n", fragment_end);fflush(err); | |
| if(substr_end>fragment_end) // are there still more? | |
| append(Fragment(fragment.lang, fragment.length)); // appending whole fragment | |
| else { // no, it was last | |
| append(Fragment(fragment.lang, substr_end-fragment_begin)); | |
| //fclose(err); | |
| return; | |
| } | |
| } | |
| } | |
| break; | |
| } | |
| //fclose(err); | |
| } | |
| // StringBody methods | // StringBody methods |
| StringBody StringBody::Format(int value) { | StringBody StringBody::Format(int value) { |
| Line 115 String::String(const String::C cstr, boo | Line 96 String::String(const String::C cstr, boo |
| append_know_length(cstr.str, cstr.length, tainted?L_TAINTED:L_CLEAN); | append_know_length(cstr.str, cstr.length, tainted?L_TAINTED:L_CLEAN); |
| } | } |
| String::String(const String& src): body(src.body) { | |
| fragments.append(src.fragments); | |
| ASSERT_STRING_INVARIANT(*this); | |
| } | |
| 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) { |
| if(!known_length) | if(!known_length) |
| return *this; | return *this; |
| // first: langs | |
| langs.append(body, lang, known_length); | |
| // next: letters themselves | |
| body.append_know_length(str, known_length); | body.append_know_length(str, known_length); |
| fragments+=Fragment(lang, known_length); | |
| ASSERT_STRING_INVARIANT(*this); | ASSERT_STRING_INVARIANT(*this); |
| return *this; | return *this; |
| Line 144 String& String::append_strdup(const char | Line 122 String& String::append_strdup(const char |
| if(!known_length) | if(!known_length) |
| return *this; | return *this; |
| // first: langs | |
| langs.append(body, lang, known_length); | |
| // next: letters themselves | |
| body.append_strdup_know_length(str, known_length); | body.append_strdup_know_length(str, known_length); |
| fragments+=Fragment(lang, known_length); | |
| ASSERT_STRING_INVARIANT(*this); | ASSERT_STRING_INVARIANT(*this); |
| return *this; | return *this; |
| Line 161 String& String::mid(size_t substr_begin, | Line 141 String& String::mid(size_t substr_begin, |
| if(substr_begin==substr_end) | if(substr_begin==substr_end) |
| return result; | return result; |
| // first: letters themselves | // first: their langs |
| result.langs.append(result.body, langs, substr_begin, substr_end); | |
| // next: letters themselves | |
| result.body=body.mid(substr_begin, substr_end-substr_begin); | result.body=body.mid(substr_begin, substr_end-substr_begin); |
| // next: their langs | |
| result.fragments.append_positions(fragments, substr_begin, substr_end); | |
| // SAPI::log("piece of '%s' from %d to %d is '%s'", | // SAPI::log("piece of '%s' from %d to %d is '%s'", |
| //cstr(), substr_begin, substr_end, result.cstr()); | //cstr(), substr_begin, substr_end, result.cstr()); |
| ASSERT_STRING_INVARIANT(result); | ASSERT_STRING_INVARIANT(result); |
| return result; | return result; |
| } | } |
| size_t String::pos(const StringBody substr, | size_t String::pos(const StringBody substr, size_t this_offset, Language lang) const { |
| size_t this_offset, Language lang) const { | |
| // first: letters themselves | |
| size_t substr_begin=body.pos(substr, this_offset); | size_t substr_begin=body.pos(substr, this_offset); |
| if(substr_begin==CORD_NOT_FOUND) | if(substr_begin==CORD_NOT_FOUND || !langs.check_lang(lang, substr_begin, substr.length())) |
| return STRING_NOT_FOUND; | return STRING_NOT_FOUND; |
| // next: check the lang when specified | return substr_begin; |
| if(lang==L_UNSPECIFIED) // ignore lang? | |
| return substr_begin; | |
| // substr must be in one fragment, and fragments' lang must = lang | |
| size_t substr_end=substr_begin+substr.length(); | |
| size_t fragment_begin=0; | |
| size_t fragment_end; | |
| for(Array_iterator<ArrayFragment::element_type> i(fragments); i.has_next(); fragment_begin=fragment_end) { | |
| const Fragment fragment=i.next(); | |
| fragment_end=fragment_begin+fragment.length; | |
| if(substr_begin<fragment_begin) // not reached fragments which may include 'result'? | |
| continue; | |
| if(substr_begin>=fragment_end) // begin of substr OUT of current fragment? | |
| continue; | |
| if(substr_end>fragment_end) // end of substr OUT of current fragment? | |
| throw Exception(0, // (*) see below | |
| this, | |
| "searching for '%s' starting from %ud problem: found begin in one fragment, but end in another", | |
| substr.cstr(), this_offset); | |
| if(fragment.lang<=lang) | |
| return substr_begin; | |
| else { // bad lang... | |
| /// WARNING: this possibly skips assert (*), but it's fast | |
| substr_begin=body.pos(substr, fragment_end/*...search AFTER for more*/); | |
| if(substr_begin==CORD_NOT_FOUND) | |
| return STRING_NOT_FOUND; | |
| size_t substr_end=substr_begin+substr.length(); | |
| // and continuing with next fragment | |
| } | |
| } | |
| return STRING_NOT_FOUND; | |
| } | } |
| size_t String::pos(const String& substr, | size_t String::pos(const String& substr, |
| Line 443 String& String::change_case(Charset& sou | Line 383 String& String::change_case(Charset& sou |
| *dest++=(char)c; | *dest++=(char)c; |
| } | } |
| result.langs=langs; | |
| result.body=new_cstr; | result.body=new_cstr; |
| result.fragments.append(fragments); | |
| return result; | return result; |
| } | } |
| Line 459 const String& String::replace(const Dict | Line 399 const String& String::replace(const Dict |
| if(Table::element_type row=dict.first_that_begins(current)) { | if(Table::element_type row=dict.first_that_begins(current)) { |
| // prematch | // prematch |
| if(size_t prematch_length=current-prematch_begin) { | if(size_t prematch_length=current-prematch_begin) { |
| result.langs.append(result.body, langs, prematch_begin-old_cstr, current-old_cstr); | |
| result.body.append_strdup_know_length(prematch_begin, prematch_length); | result.body.append_strdup_know_length(prematch_begin, prematch_length); |
| result.fragments.append_positions(fragments, prematch_begin-old_cstr, current-old_cstr); | |
| } | } |
| // match | // match |
| Line 479 const String& String::replace(const Dict | Line 419 const String& String::replace(const Dict |
| // postmatch | // postmatch |
| if(size_t postmatch_length=current-prematch_begin) { | if(size_t postmatch_length=current-prematch_begin) { |
| result.langs.append(result.body, langs, prematch_begin-old_cstr, current-old_cstr); | |
| result.body.append_strdup_know_length(prematch_begin, postmatch_length); | result.body.append_strdup_know_length(prematch_begin, postmatch_length); |
| result.fragments.append_positions(fragments, prematch_begin-old_cstr, current-old_cstr); | |
| } | } |
| ASSERT_STRING_INVARIANT(result); | ASSERT_STRING_INVARIANT(result); |
| Line 561 static int serialize_body_piece(const ch | Line 501 static int serialize_body_piece(const ch |
| return 0; | return 0; |
| }; | }; |
| String::Cm String::serialize(size_t prolog_length) const { | String::Cm String::serialize(size_t prolog_length) const { |
| #if TODO | |
| //_asm int 3; | //_asm int 3; |
| size_t buf_length= | size_t buf_length= |
| prolog_length | prolog_length |
| +sizeof(size_t) | +sizeof(size_t) |
| +fragments.count()*(sizeof(Language)+sizeof(size_t)) | +langs.count()*(sizeof(Language)+sizeof(size_t)) |
| +length(); | +length(); |
| String::Cm result(new(PointerFreeGC) char[buf_length], buf_length); | String::Cm result(new(PointerFreeGC) char[buf_length], buf_length); |
| Line 573 String::Cm String::serialize(size_t prol | Line 514 String::Cm String::serialize(size_t prol |
| char *cur=result.str+prolog_length; | char *cur=result.str+prolog_length; |
| // 2: fragments.count | // 2: langs.count |
| size_t fragments_count=fragments.count(); | size_t fragments_count=langs.count(); |
| memcpy(cur, &fragments_count, sizeof(fragments_count)); cur+=sizeof(fragments_count); | memcpy(cur, &fragments_count, sizeof(fragments_count)); cur+=sizeof(fragments_count); |
| // 3: lang info | // 3: lang info |
| for(Array_iterator<ArrayFragment::element_type> i(fragments); i.has_next(); ) { | for(Array_iterator<ArrayFragment::element_type> i(langs); i.has_next(); ) { |
| const Fragment fragment=i.next(); | const Fragment fragment=i.next(); |
| // lang | // lang |
| memcpy(cur, &fragment.lang, sizeof(fragment.lang)); cur+=sizeof(fragment.lang); | memcpy(cur, &fragment.lang, sizeof(fragment.lang)); cur+=sizeof(fragment.lang); |
| Line 590 String::Cm String::serialize(size_t prol | Line 531 String::Cm String::serialize(size_t prol |
| body.for_each(serialize_body_piece, &cur); | body.for_each(serialize_body_piece, &cur); |
| return result; | return result; |
| #endif | |
| return String::Cm(0, 0); | |
| } | } |
| bool String::deserialize(size_t prolog_length, void *buf, size_t buf_length) { | bool String::deserialize(size_t prolog_length, void *buf, size_t buf_length) { |
| #if TODO | |
| if(buf_length<=prolog_length) | if(buf_length<=prolog_length) |
| return false; | return false; |
| buf_length-=prolog_length; | buf_length-=prolog_length; |
| Line 599 bool String::deserialize(size_t prolog_l | Line 543 bool String::deserialize(size_t prolog_l |
| // 1: prolog | // 1: prolog |
| const char* cur=(const char* )buf+prolog_length; | const char* cur=(const char* )buf+prolog_length; |
| // 2: fragments.count | // 2: langs.count |
| if(buf_length<sizeof(size_t)) // fragments.count don't fit? | if(buf_length<sizeof(size_t)) // langs.count don't fit? |
| return false; | return false; |
| size_t fragments_count=*reinterpret_cast<const size_t*>(cur); cur+=sizeof(size_t); | size_t fragments_count=*reinterpret_cast<const size_t*>(cur); cur+=sizeof(size_t); |
| buf_length-=sizeof(size_t); | buf_length-=sizeof(size_t); |
| Line 615 bool String::deserialize(size_t prolog_l | Line 559 bool String::deserialize(size_t prolog_l |
| Language lang=*reinterpret_cast<const Language *>(cur); cur+=sizeof(Language); | Language lang=*reinterpret_cast<const Language *>(cur); cur+=sizeof(Language); |
| size_t fragment_length=*reinterpret_cast<const size_t*>(cur); cur+=sizeof(size_t); | size_t fragment_length=*reinterpret_cast<const size_t*>(cur); cur+=sizeof(size_t); |
| fragments+=Fragment(lang, fragment_length); | langs+=Fragment(lang, fragment_length); |
| total_length+=fragment_length; | total_length+=fragment_length; |
| buf_length-=piece_length; | buf_length-=piece_length; |
| Line 630 bool String::deserialize(size_t prolog_l | Line 574 bool String::deserialize(size_t prolog_l |
| ASSERT_STRING_INVARIANT(*this); | ASSERT_STRING_INVARIANT(*this); |
| return true; | return true; |
| #endif | |
| return false; | |
| } | } |