summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <sasha@asksasha.com>2006-01-13 12:25:51 -0700
committerunknown <sasha@asksasha.com>2006-01-13 12:25:51 -0700
commitd5850475d1711ebb2883b6697e9ad188a1df8cbf (patch)
tree09d6bc555ffa0dadbd4acdbdeb8991c45cdbec7d
parent91881b44c347e173d5d49aa9e5351a42267ed0a2 (diff)
downloadmariadb-git-d5850475d1711ebb2883b6697e9ad188a1df8cbf.tar.gz
patch for replace_regex in mysqltest
client/mysqltest.c: patch for replace_regex
-rw-r--r--client/mysqltest.c385
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(&reg,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) &reg))
+ 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;