diff options
| author | root <root@dc13.lemmi> | 2020-07-21 10:00:46 +0200 |
|---|---|---|
| committer | root <root@dc13.lemmi> | 2020-07-21 10:00:46 +0200 |
| commit | 1192c4575ea7afdf38e3fa0df4587a08620af11e (patch) | |
| tree | 6910a62487c282d0840d2e668aa7eb40b7c8a3fd /project/dclib/dclib-regex.c | |
| parent | 76de8a89f7c1d1b4522eb66e8f89d248e8c1781f (diff) | |
SZS v2.18a
Diffstat (limited to 'project/dclib/dclib-regex.c')
| -rw-r--r-- | project/dclib/dclib-regex.c | 465 |
1 files changed, 465 insertions, 0 deletions
diff --git a/project/dclib/dclib-regex.c b/project/dclib/dclib-regex.c new file mode 100644 index 0000000..d9bdf99 --- /dev/null +++ b/project/dclib/dclib-regex.c @@ -0,0 +1,465 @@ + +/*************************************************************************** + * * + * _____ ____ * + * | __ \ / __ \ _ _ _____ * + * | | \ \ / / \_\ | | | | _ \ * + * | | \ \| | | | | | |_| | * + * | | | || | | | | | ___/ * + * | | / /| | __ | | | | _ \ * + * | |__/ / \ \__/ / | |___| | |_| | * + * |_____/ \____/ |_____|_|_____/ * + * * + * Wiimms source code library * + * * + *************************************************************************** + * * + * Copyright (c) 2012-2020 by Dirk Clemens <wiimm@wiimm.de> * + * * + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt * + * * + ***************************************************************************/ + +#define _GNU_SOURCE 1 + +#include "dclib-regex.h" + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// some macro definitions /////////////// +/////////////////////////////////////////////////////////////////////////////// + +#undef REGEX_FREE +#undef REOPT_ICASE +#undef MATCH_BEG +#undef MATCH_END + +#if DCLIB_USE_PCRE + #define REGEX_FREE pcre_free + #define REOPT_ICASE PCRE_CASELESS + #define MATCH_BEG(i) match[2*i] + #define MATCH_END(i) match[2*i+1] +#else + #define REGEX_FREE regfree + #define REOPT_ICASE REG_ICASE + #define MATCH_BEG(i) match[i].rm_so + #define MATCH_END(i) match[i].rm_eo +#endif + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// struct Regex_t /////////////// +/////////////////////////////////////////////////////////////////////////////// + +void InitializeRegex ( Regex_t *re ) +{ + DASSERT(re); + memset(re,0,sizeof(*re)); + re->re_list = re->re_pool; + re->re_size = sizeof(re->re_pool)/sizeof(*re->re_pool); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ResetRegex ( Regex_t *re ) +{ + DASSERT(re); + + RegexElem_t *e, *eend = re->re_list + re->re_used; + for ( e = re->re_list; e < eend; e++ ) + { + #if DCLIB_USE_PCRE + if (e->regex) + pcre_free(e->regex); + #else + regfree(&e->regex); + #endif + + FreeString(e->pattern); + FreeString(e->replace.ptr); + FREE(e->repl); + } + + if ( re->re_list != re->re_pool ) + FREE(re->re_list); + + InitializeRegex(re); +} + +/////////////////////////////////////////////////////////////////////////////// + +static RegexElem_t * GetNextRegexElem ( Regex_t *re ) +{ + DASSERT(re); + if ( re->re_used >= re->re_size ) + { + re->re_size = 3*re->re_size/2 + 10; + if ( re->re_list == re->re_pool ) + { + re->re_list = MALLOC( sizeof(*re->re_list) * re->re_size ); + memcpy( re->re_list, re->re_pool, sizeof(*re->re_list) * re->re_used ); + } + else + re->re_list = REALLOC( re->re_list, sizeof(*re->re_list) * re->re_size ); + } + + RegexElem_t *e = re->re_list + re->re_used; + memset(e,0,sizeof(*e)); + return e; +} + +/////////////////////////////////////////////////////////////////////////////// + +static RegexReplace_t * GetNextRegexRepl + ( RegexElem_t *elem, char *ptr, int len, int ref ) +{ + DASSERT(elem); + if ( !len && ref < 0 ) + return 0; + + if ( elem->repl_used >= elem->repl_size ) + { + elem->repl_size = 3*elem->repl_size/2 + 10; + elem->repl = REALLOC( elem->repl, sizeof(*elem->repl) * elem->repl_size ); + } + + RegexReplace_t *repl = elem->repl + elem->repl_used++; + repl->str.ptr = ptr; + repl->str.len = len; + repl->ref = ref; + PRINT("REPL[%d]: |%.*s| %d\n",elem->repl_used-1,len,ptr,ref); + return repl; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanRegex ( Regex_t *re, bool init_re, ccp regex ) +{ + DASSERT(re); + if (init_re) + InitializeRegex(re); + else + ResetRegex(re); + + if ( !regex || !*regex ) + return ERR_NOTHING_TO_DO; + + struct { FastBuf_t b; char space[500]; } temp; + InitializeFastBuf(&temp,sizeof(temp)); + + //--- scanning + + enumError err = ERR_OK; + for(;;) + { + while ( isspace(*regex) || *regex == ';' ) + regex++; + if (!*regex) + break; + + noPRINT("RE: ANALYZE #%u/%u: %s\n",re->re_used, re->re_size,regex); + + char sep = *regex++; + while ( *regex && *regex != sep ) + { + char ch = *regex++; + if ( ch == '\\' && *regex == sep ) + ch = *regex++; + AppendCharFastBuf(&temp.b,ch); + } + + if ( *regex != sep ) + { + err = ERR_SYNTAX; + goto exit; + } + + ccp repl = ++regex; + while ( *regex && *regex != sep ) + regex++; + const uint repl_len = regex - repl; + + RegexElem_t *elem = GetNextRegexElem(re); + + if ( *regex == sep ) + { + regex++; + while ( *regex && *regex != ';' ) + switch (*regex++) + { + case 'g': elem->global = true; break; + case 'i': elem->icase = true; elem->opt |= REOPT_ICASE; break; + } + } + + PRINT("RE: PATTERN #%u/%u: [%s] %s -> %.*s : %s\n", + re->re_used, re->re_size, + GetFastBufStatus(&temp.b), + GetFastBufString(&temp.b), + repl_len, repl, regex ); + + // store data as strings + elem->pattern = MEMDUP(temp.b.buf,temp.b.ptr-temp.b.buf); + elem->replace.ptr = repl_len ? MEMDUP(repl,repl_len) : EmptyString; + elem->replace.len = repl_len; + re->re_used++; + ClearFastBuf(&temp.b); + } + + + //--- finalize + + re->valid = true; + + uint e; + RegexElem_t *elem; + for ( e = 0, elem = re->re_list; e < re->re_used; e++, elem++ ) + { + #if DCLIB_USE_PCRE + + ccp errptr; + int erroffset; + re->regex = pcre_compile(elem->pattern,opt,&errptr,&erroffset,0); + if (!re->regex) + { + PRINT("PCRE error: %s: %s\n",errptr,pattern+erroffset); + return ERR_SEMANTIC; + err = ERR_SEMANTIC; + goto exit; + } + + #else + + int stat = regcomp(&elem->regex,elem->pattern,elem->opt|REG_EXTENDED); + if (stat) + { + #if HAVE_PRINT0 + char error[100]; + regerror(stat,&re->regex,errormsizeof(error)); + PRINT("PCRE error: %s: %s\n",errptr,pattern+erroffset); + #endif + re->valid = false; + err = ERR_SEMANTIC; + } + else + elem->valid = true; + #endif + + + //--- analyse replace + + char *ptr = (char*)elem->replace.ptr; + char *dest = ptr; + char *start = dest; + char *end = ptr + elem->replace.len; + + while ( ptr < end ) + { + while ( ptr < end && *ptr != '\\' && *ptr != '$' ) + *dest++ = *ptr++; + if ( ptr == end ) + { + GetNextRegexRepl(elem,start,dest-start,-1); + break; + } + + if ( *ptr == ptr[1] ) + { + ptr++; + *dest++ = *ptr++; + } + else if ( ptr[1] >= '0' && ptr[1] <= '9' ) + { + GetNextRegexRepl(elem,start,dest-start,ptr[1]-'0'); + start = dest; + ptr += 2; + } + else if ( ptr[1] == '{' ) + { + char *p = ptr+2; + if ( *p >= '0' && *p <= '9' ) + { + uint num = *p++ - '0'; + if ( *p >= '0' && *p <= '9' ) + num = 10*num + *p++ - '0'; + if ( p < end && *p == '}' ) + { + GetNextRegexRepl(elem,start,dest-start,num); + start = dest; + ptr = p+1; + continue; + } + } + *dest++ = *ptr++; + } + else + *dest++ = *ptr++; + } + + if ( dest != EmptyString ) + *dest = 0; + elem->replace.len = dest - elem->replace.ptr; + } + + PRINT("RE: n=%d, valid=%d\n",re->re_used,re->valid); + + exit: + ResetFastBuf(&temp.b); + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +int ReplaceRegex +( + Regex_t *re, // valid Regex_t + FastBuf_t *res, // return buffer, cleared + ccp src, + int src_len // -1: use strlen() +) +{ + DASSERT(re); + DASSERT(res); + + + //--- sanity checks + + if (!res) + return -ERR_INVALID_DATA; + + ClearFastBuf(res); + + if ( !re || !re->valid ) + return -ERR_INVALID_DATA; + + if ( !src || !*src ) + return 0; + + if ( src_len < 0 ) + src_len = strlen(src); + + + //--- prepare data + + enumError err = ERR_OK; + uint count = 0; + + struct { FastBuf_t b; char space[500]; } temp; + InitializeFastBuf(&temp,sizeof(temp)); + FastBuf_t *dest = res; + + #if DCLIB_USE_PCRE + DASSERT(re->regex); + enum { N_MATCH = 100 }; + int match[N_MATCH]; + #else + enum { N_MATCH = 100 }; + regmatch_t match[N_MATCH]; + #endif + + + //--- exec RE + + uint e; + RegexElem_t *elem; + for ( e = 0, elem = re->re_list; e < re->re_used; e++, elem++ ) + { + uint pos = 0, copied = 0; + while( pos < src_len ) + { + memset(match,0,sizeof(match)); + + #if DCLIB_USE_PCRE + int stat = pcre_exec(re->regex,0,src,src_len,pos,0,match,N_MATCH); + noPRINT("RE: stat=%2d : %2d %2d : %2d %2d : %2d %2d\n", + stat, match[0],match[1], match[2],match[3], match[4],match[5] ); + if ( stat < 0 ) + { + if ( stat == PCRE_ERROR_NOMATCH ) + break; + err = -ERR_ERROR; + goto exit; + } + const uint match_beg = match[0]; + const uint match_end = match[1]; + + #else + + int stat = regexec(&elem->regex,src+pos,N_MATCH,match,0); + PRINT("RE: pos=%2d, stat=%2d : %2d %2d : %2d %2d : %2d %2d\n", + pos, stat, match[0].rm_so,match[0].rm_eo, + match[1].rm_so,match[1].rm_eo, match[2].rm_so,match[2].rm_eo ); + if (stat) + { + if ( stat == REG_NOMATCH ) + break; + err = -ERR_ERROR; + goto exit; + } + const uint match_beg = match[0].rm_so + pos; + const uint match_end = match[0].rm_eo + pos; + + #endif + + if ( match_beg > copied ) + AppendFastBuf(dest,src+copied,match_beg-copied); + copied = match_end; + + RegexReplace_t *repl = elem->repl; + RegexReplace_t *repl_end = repl + elem->repl_used; + for ( ; repl < repl_end; repl++ ) + { + AppendMemFastBuf(dest,repl->str); + #if DCLIB_USE_PCRE + #error + #else + if ( repl->ref >= 0 && repl->ref < N_MATCH ) + { + const regmatch_t *m = match + repl->ref; + if ( m->rm_so >= 0 ) + AppendFastBuf( dest, + src + m->rm_so + pos, + m->rm_eo - m->rm_so ); + } + #endif + } + + pos = match_end + ( match_beg == match_end ); + count++; + + if (!elem->global) + break; + } + + if ( src_len > copied ) + AppendFastBuf(dest,src+copied,src_len-copied); + + PRINT("DEST: %s\n",GetFastBufString(dest)); + src = GetFastBufString(dest); + src_len = GetFastBufLen(dest); + dest = dest == res ? &temp.b : res; + ClearFastBuf(dest); + } + + exit:; + AssignFastBuf(res,src,src_len); + return err < 0 ? err : count; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// END /////////////// +/////////////////////////////////////////////////////////////////////////////// + |
