diff options
author | unknown <sasha@asksasha.com> | 2006-01-13 12:25:51 -0700 |
---|---|---|
committer | unknown <sasha@asksasha.com> | 2006-01-13 12:25:51 -0700 |
commit | d5850475d1711ebb2883b6697e9ad188a1df8cbf (patch) | |
tree | 09d6bc555ffa0dadbd4acdbdeb8991c45cdbec7d | |
parent | 91881b44c347e173d5d49aa9e5351a42267ed0a2 (diff) | |
download | mariadb-git-d5850475d1711ebb2883b6697e9ad188a1df8cbf.tar.gz |
patch for replace_regex in mysqltest
client/mysqltest.c:
patch for replace_regex
-rw-r--r-- | client/mysqltest.c | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/client/mysqltest.c b/client/mysqltest.c index 3a4ce5ce7cf..d57213821cf 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -181,6 +181,25 @@ static test_file file_stack[MAX_INCLUDE_DEPTH]; static test_file* cur_file; static test_file* file_stack_end; +struct st_regex +{ + char* pattern; + char* replace; + int icase; +}; + +struct st_replace_regex +{ + DYNAMIC_ARRAY regex_arr; + char* buf; + char* even_buf; + uint even_buf_len; + char* odd_buf; + uint odd_buf_len; +}; + +struct st_replace_regex *glob_replace_regex= 0; + static uint lineno_stack[MAX_INCLUDE_DEPTH]; static char TMPDIR[FN_REFLEN]; static char delimiter[MAX_DELIMITER]= DEFAULT_DELIMITER; @@ -218,6 +237,9 @@ static int ps_match_re(char *); static char *ps_eprint(int); static void ps_free_reg(void); +static int reg_replace(char** buf_p, int* buf_len_p, char *pattern, char *replace, + char *string, int icase); + static const char *embedded_server_groups[]= { "server", @@ -326,6 +348,7 @@ Q_EXIT, Q_DISABLE_RECONNECT, Q_ENABLE_RECONNECT, Q_IF, Q_DISABLE_PARSING, Q_ENABLE_PARSING, +Q_REPLACE_REGEX, Q_UNKNOWN, /* Unknown command. */ Q_COMMENT, /* Comments, ignored. */ @@ -419,6 +442,7 @@ const char *command_names[]= "if", "disable_parsing", "enable_parsing", + "replace_regex", 0 }; @@ -460,6 +484,7 @@ struct st_replace *init_replace(my_string *from, my_string *to, uint count, uint replace_strings(struct st_replace *rep, my_string *start, uint *max_length, const char *from); void free_replace(); +static void free_replace_regex(); static int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name); void free_pointer_array(POINTER_ARRAY *pa); static int initialize_replace_buffer(void); @@ -1772,6 +1797,165 @@ static char *get_string(char **to_ptr, char **from_ptr, DBUG_RETURN(start); } +#define PARSE_REGEX_ARG \ + while (p < expr_end) \ + {\ + char c= *p;\ + if (c == '/')\ + {\ + if (last_c == '\\')\ + {\ + buf_p[-1]= '/';\ + }\ + else\ + {\ + *buf_p++ = 0;\ + break;\ + } \ + } \ + else\ + *buf_p++ = c;\ + \ + last_c= c;\ + p++;\ + } \ + +static struct st_replace_regex* init_replace_regex(char* expr) +{ + struct st_replace_regex* res; + char* buf,*expr_end; + char* p; + char* buf_p; + uint expr_len= strlen(expr); + char last_c = 0; + struct st_regex reg; + + if (!(res=(struct st_replace_regex*)my_malloc( + sizeof(*res)+expr_len ,MYF(MY_FAE+MY_WME)))) + return 0; + my_init_dynamic_array(&res->regex_arr,sizeof(struct st_regex),128,128); + + buf= (char*)res + sizeof(*res); + expr_end= expr + expr_len; + p= expr; + buf_p= buf; + + /* for each regexp substitution statement */ + while (p < expr_end) + { + bzero(®,sizeof(reg)); + /* find the start of the statement */ + while (p < expr_end) + { + if (*p == '/') + break; + p++; + } + + if (p == expr_end || ++p == expr_end) + { + if (res->regex_arr.elements) + break; + else + goto err; + } + /* we found the start */ + reg.pattern= buf_p; + + PARSE_REGEX_ARG + + if (p == expr_end || ++p == expr_end) + goto err; + + /* buf_p now points to the replacement pattern terminated with \0 */ + reg.replace= buf_p; + + PARSE_REGEX_ARG + + if (p == expr_end) + goto err; + + /* skip the ending '/' in the statement */ + p++; + + if (p < expr_end && *p == 'i') + reg.icase= 1; + + /* done parsing the statement, now place it in regex_arr */ + if (insert_dynamic(&res->regex_arr,(gptr) ®)) + die("Out of memory"); + } + res->odd_buf_len= res->even_buf_len= 8192; + res->even_buf= (char*)my_malloc(res->even_buf_len,MYF(MY_WME+MY_FAE)); + res->odd_buf= (char*)my_malloc(res->odd_buf_len,MYF(MY_WME+MY_FAE)); + res->buf= res->even_buf; + + return res; + +err: + my_free((gptr)res,0); + return 0; +} + +/* + TODO: at some point figure out if there is a way to do everything + in one pass + */ + +static int multi_reg_replace(struct st_replace_regex* r,char* val) +{ + uint i; + char* in_buf, *out_buf; + int* buf_len_p; + + in_buf= val; + out_buf= r->even_buf; + buf_len_p= &r->even_buf_len; + r->buf= 0; + + for (i= 0; i < r->regex_arr.elements; i++) + { + struct st_regex re; + char* save_out_buf= out_buf; + + get_dynamic(&r->regex_arr,(gptr)&re,i); + + if (!reg_replace(&out_buf,buf_len_p,re.pattern,re.replace, + in_buf,re.icase)) + { + //printf("out_buf=%s\n", out_buf); + /* the buffer has been reallocated, make adjustements */ + if (save_out_buf != out_buf) + { + if (save_out_buf == r->even_buf) + r->even_buf= out_buf; + else + r->odd_buf= out_buf; + } + + r->buf= out_buf; + if (in_buf == val) + in_buf= r->odd_buf; + + swap_variables(char*,in_buf,out_buf); + + buf_len_p= (out_buf == r->even_buf) ? &r->even_buf_len : + &r->odd_buf_len; + } + } + + return (r->buf == 0); +} + +static void get_replace_regex(struct st_query *q) +{ + char *expr= q->first_argument; + free_replace_regex(); + if (!(glob_replace_regex=init_replace_regex(expr))) + die("Could not init replace_regex"); + q->last_argument= q->end; +} + /* Get arguments for replace. The syntax is: @@ -1824,6 +2008,18 @@ static void get_replace(struct st_query *q) DBUG_VOID_RETURN; } +static void free_replace_regex() +{ + if (glob_replace_regex) + { + my_free(glob_replace_regex->even_buf,MYF(MY_ALLOW_ZERO_PTR)); + my_free(glob_replace_regex->odd_buf,MYF(MY_ALLOW_ZERO_PTR)); + my_free((char*) glob_replace_regex,MYF(0)); + glob_replace_regex=0; + } +} + + void free_replace() { DBUG_ENTER("free_replace"); @@ -2138,6 +2334,7 @@ int connect_n_handle_errors(struct st_query *q, MYSQL* con, const char* host, err: free_replace(); + free_replace_regex(); if (ds == &ds_tmp) dynstr_free(&ds_tmp); return error; @@ -2986,6 +3183,178 @@ void reject_dump(const char *record_file, char *buf, int size) str_to_file(fn_format(reject_file, record_file,"",".reject",2), buf, size); } +static void check_regerr(my_regex_t* r, int err) +{ + char err_buf[1024]; + + if (err) + { + my_regerror(err,r,err_buf,sizeof(err_buf)); + fprintf(stderr, "Regex error: %s\n", err_buf); + exit(1); + } +} + +#define SECURE_REG_BUF if (buf_len < need_buf_len)\ + {\ + int off= res_p - buf;\ + buf= (char*)my_realloc(buf,need_buf_len,MYF(MY_WME+MY_FAE));\ + res_p= buf + off;\ + buf_len= need_buf_len;\ + }\ + +static int reg_replace(char** buf_p, int* buf_len_p, char *pattern, char *replace, + char *string, int icase) +{ + my_regex_t r; + my_regmatch_t* subs; + char* buf_end, *replace_end; + char* buf= *buf_p; + int len; + int buf_len,need_buf_len; + int cflags= REG_EXTENDED; + int err_code; + char* res_p,*str_p,*str_end; + + buf_len= *buf_len_p; + len= strlen(string); + str_end= string + len; + need_buf_len= len * 2 + 1; + res_p= buf; + + SECURE_REG_BUF + + buf_end = buf + buf_len; + + if (icase) + cflags |= REG_ICASE; + + if ((err_code=my_regcomp(&r,pattern,cflags,&my_charset_latin1))) + { + check_regerr(&r,err_code); + return 1; + } + + subs= (my_regmatch_t*)my_malloc(sizeof(my_regmatch_t) * (r.re_nsub+1), + MYF(MY_WME+MY_FAE)); + + *res_p= 0; + str_p= string; + replace_end= replace + strlen(replace); + + while (!err_code) + { + err_code= my_regexec(&r,str_p,r.re_nsub+1,subs, + (str_p == string) ? REG_NOTBOL : 0); + + if (err_code && err_code != REG_NOMATCH) + { + check_regerr(&r,err_code); + my_regfree(&r); + return 1; + } + + if (!err_code) + { + char* expr_p= replace; + int c; + + need_buf_len= (res_p - buf) + subs[0].rm_so; + + while (expr_p < replace_end) + { + int back_ref_num= -1; + c= *expr_p; + + if (c == '\\' && expr_p + 1 < replace_end) + { + back_ref_num= expr_p[1] - '0'; + } + + if (back_ref_num >= 0 && back_ref_num <= (int)r.re_nsub) + { + int start_off,end_off; + if ((start_off=subs[back_ref_num].rm_so) > -1 && + (end_off=subs[back_ref_num].rm_eo) > -1) + { + need_buf_len += (end_off - start_off); + } + expr_p += 2; + } + else + { + expr_p++; + need_buf_len++; + } + } + need_buf_len++; + SECURE_REG_BUF + + if (subs[0].rm_so) + { + memcpy(res_p,str_p,subs[0].rm_so); + res_p += subs[0].rm_so; + } + + expr_p= replace; + + while (expr_p < replace_end) + { + int back_ref_num= -1; + c= *expr_p; + + if (c == '\\' && expr_p + 1 < replace_end) + { + back_ref_num= expr_p[1] - '0'; + } + + if (back_ref_num >= 0 && back_ref_num <= (int)r.re_nsub) + { + int start_off,end_off; + if ((start_off=subs[back_ref_num].rm_so) > -1 && + (end_off=subs[back_ref_num].rm_eo) > -1) + { + int block_len= end_off - start_off; + memcpy(res_p,str_p + start_off, block_len); + res_p += block_len; + } + expr_p += 2; + } + else + { + *res_p++ = *expr_p++; + } + } + + if (subs[0].rm_so == subs[0].rm_eo) + { + if (str_p + subs[0].rm_so >= str_end) + break; + str_p += subs[0].rm_eo ; + *res_p++ = *str_p++; + } + else + { + str_p += subs[0].rm_eo; + } + } + else /* no match this time */ + { + int left_in_str= str_end-str_p; + need_buf_len= (res_p-buf) + left_in_str; + SECURE_REG_BUF + memcpy(res_p,str_p,left_in_str); + res_p += left_in_str; + str_p= str_end; + } + } + my_regfree(&r); + *res_p= 0; + *buf_p= buf; + *buf_len_p= buf_len; + return 0; +} + /* Append the string to ds, with optional replace */ @@ -2999,6 +3368,16 @@ static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, die("Out of memory in replace"); val=out_buff; } + + if (glob_replace_regex) + { + if (!multi_reg_replace(glob_replace_regex,(char*)val)) + { + val= glob_replace_regex->buf; + len= strlen(val); + } + } + dynstr_append_mem(ds, val, len); } @@ -3261,6 +3640,7 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) end: free_replace(); + free_replace_regex(); last_result=0; if (ds == &ds_tmp) dynstr_free(&ds_tmp); @@ -3717,6 +4097,7 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) end: free_replace(); + free_replace_regex(); last_result=0; if (ds == &ds_tmp) dynstr_free(&ds_tmp); @@ -4261,6 +4642,10 @@ int main(int argc, char **argv) case Q_REPLACE: get_replace(q); break; + case Q_REPLACE_REGEX: + get_replace_regex(q); + break; + case Q_REPLACE_COLUMN: get_replace_column(q); break; |