|
|
| version 1.62, 2001/04/03 09:58:10 | version 1.74, 2001/04/06 13:41:32 |
|---|---|
| Line 10 | Line 10 |
| #include "pa_config_includes.h" | #include "pa_config_includes.h" |
| #include <locale.h> | #include "pcre.h" |
| #include "pa_pool.h" | #include "pa_pool.h" |
| #include "pa_string.h" | #include "pa_string.h" |
| Line 22 | Line 22 |
| #include "pa_table.h" | #include "pa_table.h" |
| #include "pa_threads.h" | #include "pa_threads.h" |
| #include "pcre.h" | |
| //#include "pa_sapi.h" | //#include "pa_sapi.h" |
| // consts | |
| const int MAX_MATCH_COLUMNS=20; | |
| // String | // String |
| String::String(Pool& apool, const char *src, bool tasize_ted) : | String::String(Pool& apool, const char *src, bool tasize_ted) : |
| Line 203 int String::cmp(int& partial, const Stri | Line 197 int String::cmp(int& partial, const Stri |
| break; | break; |
| if(pos+a_row->item.size > this_offset) { | if(pos+a_row->item.size > this_offset) { |
| if(lang!=UL_UNKNOWN && a_row->item.lang!=lang) | if(lang!=UL_UNSPECIFIED && a_row->item.lang!=lang) |
| return -1; // wrong lang -- bail out | return -1; // wrong lang -- bail out |
| int size_diff= | int size_diff= |
| Line 283 int String::cmp(int& partial, const char | Line 277 int String::cmp(int& partial, const char |
| break; | break; |
| if(pos+a_row->item.size > this_offset) { | if(pos+a_row->item.size > this_offset) { |
| if(lang!=UL_UNKNOWN && a_row->item.lang!=lang) | if(lang!=UL_UNSPECIFIED && a_row->item.lang!=lang) |
| return -1; // wrong lang -- bail out | return -1; // wrong lang -- bail out |
| int size_diff= | int size_diff= |
| Line 346 const Origin& String::origin() const { | Line 340 const Origin& String::origin() const { |
| } | } |
| #endif | #endif |
| String& String::piece(size_t start, size_t finish) const { | String& String::mid(size_t start, size_t finish) const { |
| start=max(0, start); | start=max(0, start); |
| finish=min(size(), finish); | finish=min(size(), finish); |
| if(start==finish) | if(start==finish) |
| Line 419 void String::split(Array& result, | Line 413 void String::split(Array& result, |
| int pos_before; | int pos_before; |
| // while we have 'delim'... | // while we have 'delim'... |
| for(; (pos_before=pos(delim, delim_size, pos_after, lang))>=0 && limit; limit--) { | for(; (pos_before=pos(delim, delim_size, pos_after, lang))>=0 && limit; limit--) { |
| result+=&piece(pos_after, pos_before); | result+=&mid(pos_after, pos_before); |
| pos_after=pos_before+delim_size; | pos_after=pos_before+delim_size; |
| } | } |
| // last piece | // last piece |
| if(pos_after<size() && limit) { | if(pos_after<size() && limit) { |
| result+=&piece(pos_after, size()); | result+=&mid(pos_after, size()); |
| pos_after=size(); | pos_after=size(); |
| } | } |
| if(pos_after_ref) | if(pos_after_ref) |
| Line 445 void String::split(Array& result, | Line 439 void String::split(Array& result, |
| int pos_before; | int pos_before; |
| // while we have 'delim'... | // while we have 'delim'... |
| for(; (pos_before=pos(delim, pos_after, lang))>=0 && limit; limit--) { | for(; (pos_before=pos(delim, pos_after, lang))>=0 && limit; limit--) { |
| result+=&piece(pos_after, pos_before); | result+=&mid(pos_after, pos_before); |
| pos_after=pos_before+delim.size(); | pos_after=pos_before+delim.size(); |
| } | } |
| // last piece | // last piece |
| if(pos_after<size() && limit) { | if(pos_after<size() && limit) { |
| result+=&piece(pos_after, size()); | result+=&mid(pos_after, size()); |
| pos_after=size(); | pos_after=size(); |
| } | } |
| if(pos_after_ref) | if(pos_after_ref) |
| Line 462 void String::split(Array& result, | Line 456 void String::split(Array& result, |
| } | } |
| } | } |
| /// @test setlocale param to auto.p @test pcre_malloc & pcre_free substs | /// @test really @b test: s x m [tested: i & g ] |
| static void regex_options(char *options, int *result){ | |
| struct Regex_option { | |
| char key; | |
| int clear, set; | |
| int *result; | |
| } regex_option[]={ | |
| {'i', 0, PCRE_CASELESS, result}, // a=A | |
| {'s', 0, PCRE_DOTALL, result}, // \n\n$ | |
| {'x', 0, PCRE_EXTENDED, result}, // whitespace in regex ignored | |
| {'m', PCRE_DOTALL, PCRE_MULTILINE, result}, // ^aaa\n$^bbb\n$ | |
| {'g', 0, true, result+1}, // many rows | |
| {0}, | |
| }; | |
| result[0]=PCRE_EXTRA | PCRE_DOTALL; | |
| result[1]=0; | |
| if(options) | |
| for(Regex_option *o=regex_option; o->key; o++) | |
| if( | |
| strchr(options, o->key) || | |
| strchr(options, toupper(o->key))) { | |
| *(o->result)&=~o->clear; | |
| *(o->result)|=o->set; | |
| } | |
| } | |
| /** | |
| returns true if fills table. | |
| table format is defined and fixed[can be used by others]: | |
| @verbatim | |
| pre-match/match/post-match/1/2/3/... | |
| @endverbatim | |
| */ | |
| bool String::match(const String *aorigin, | bool String::match(const String *aorigin, |
| const String& regexp, | const String& regexp, |
| const String& options, | const String *options, |
| Table **table) const { | Table **table, |
| SYNCHRONIZED(true); | Row_action row_action, void *info) const { |
| static const unsigned char *tables=0; | |
| if(!tables) { | if(!regexp.size()) |
| setlocale(LC_CTYPE, "ru"); | THROW(0, 0, |
| tables = pcre_maketables(); | aorigin, |
| } | "regexp is empty"); |
| const char *pattern=regexp.cstr(); | const char *pattern=regexp.cstr(UL_AS_IS); |
| const char *errptr; | const char *errptr; |
| int erroffset; | int erroffset; |
| pcre *code=pcre_compile(pattern, 0, | int option_bits[2]; regex_options(options?options->cstr():0, option_bits); |
| pcre *code=pcre_compile(pattern, option_bits[0], | |
| &errptr, &erroffset, | &errptr, &erroffset, |
| tables); | pcre_tables); |
| if(!code) | if(!code) |
| THROW(0, 0, | THROW(0, 0, |
| ®exp.piece(erroffset, regexp.size()), | ®exp.mid(erroffset, regexp.size()), |
| errptr); | "regular expression syntax error - %s", errptr); |
| int ovecsize; | int info_substrings=pcre_info(code, 0, 0); |
| int *ovector=(int *)malloc(sizeof(int)*(ovecsize=(1/*.match*/+MAX_MATCH_COLUMNS)*3)); | if(info_substrings<0) { |
| const char *subject=cstr(); | (*pcre_free)(code); |
| int length=strlen(subject); | THROW(0, 0, |
| int exec_result=pcre_exec(code, 0, | aorigin, |
| subject, length, 0/*startoffset*/, | "pcre_info error #%d", |
| 0/*options*/, ovector, ovecsize); | info_substrings); |
| if(exec_result==PCRE_ERROR_NOMATCH) { | |
| *table=0; | |
| return false; | |
| } | } |
| if(exec_result<0) | int startoffset=0; |
| THROW(0, 0, | const char *subject=cstr(UL_AS_IS); |
| 0, | int length=strlen(subject); |
| "pcre_exec failed"); | int ovecsize; |
| int *ovector=(int *)malloc(sizeof(int)* | |
| (ovecsize=(1/*match*/+info_substrings)*3)); | |
| if(exec_result==0) | { // create table |
| THROW(0, 0, | Array& columns=*NEW Array(pool()); |
| aorigin, | columns+=string_pre_match_name; |
| "produced more substrings than maximum handled by Parser, which is %d", | columns+=string_match_name; |
| MAX_MATCH_COLUMNS); | columns+=string_post_match_name; |
| for(int i=1; i<=info_substrings; i++) { | |
| char *column=(char *)malloc(MAX_NUMBER); | |
| snprintf(column, MAX_NUMBER, "%d", i); | |
| columns+=NEW String(pool(), column); // .i column name | |
| } | |
| *table=NEW Table(pool(), aorigin, &columns); | |
| } | |
| Array& columns=*NEW Array(pool()); | int exec_option_bits=0; |
| columns+=string_match_name; // .match column name | while(true) { |
| Array& row=*NEW Array(pool()); | int exec_substrings=pcre_exec(code, 0, |
| row+=&piece(ovector[0], ovector[1]); // match column value | subject, length, startoffset, |
| exec_option_bits, ovector, ovecsize); | |
| for(int i=1; i<exec_result; i++) { | |
| char *column=(char *)malloc(MAX_NUMBER); | if(exec_substrings==PCRE_ERROR_NOMATCH) { |
| snprintf(column, MAX_NUMBER, "%d", i); | (*pcre_free)(code); |
| columns+=NEW String(pool(), column); // .i column name | (*row_action)(**table, 0/*last time, no row*/, 0, 0, info); |
| row+=&piece(ovector[i*2+0], ovector[i*2+1]); // .i column value | return option_bits[1]!=0; // global=true+table, not global=false |
| } | |
| if(exec_substrings<0) { | |
| (*pcre_free)(code); | |
| THROW(0, 0, | |
| aorigin, | |
| "regular expression execute error #%d", | |
| exec_substrings); | |
| } | |
| Array& row=*NEW Array(pool()); | |
| row+=&mid(0, ovector[0]); // .pre-match column value | |
| row+=&mid(ovector[0], ovector[1]); // .match | |
| row+=&mid(ovector[1], size()); // .post-match | |
| for(int i=1; i<exec_substrings; i++) { | |
| // -1:-1 case handled peacefully by mid() itself | |
| row+=&mid(ovector[i*2+0], ovector[i*2+1]); // .i column value | |
| } | |
| (*row_action)(**table, &row, startoffset, ovector[0], info); | |
| if(!option_bits[1] || !(startoffset=ovector[1])) { // not global | going to hang | |
| (*pcre_free)(code); | |
| (*row_action)(**table, 0/*last time, no row*/, 0, 0, info); | |
| return true; | |
| } | |
| /* | |
| if(option_bits[0] & PCRE_MULTILINE) | |
| exec_option_bits|=PCRE_NOTBOL; // start of subject+startoffset not BOL | |
| */ | |
| } | } |
| *table=NEW Table(pool(), aorigin, &columns); | |
| (**table)+=&row; | |
| return true; | |
| } | } |