summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
authorunknown <monty@donna.mysql.com>2001-02-13 12:40:31 +0200
committerunknown <monty@donna.mysql.com>2001-02-13 12:40:31 +0200
commit8ece82e4dcef6b7dd097350890e27b593ec079b1 (patch)
tree9cf9d3143b5b610ceb70f384c70b2b444eacc2ac /client
parentda06513a8476198501c17de8386d3bd24477e122 (diff)
parent01eff509a044abb9ccf28026ee5c41d8a59afc18 (diff)
downloadmariadb-git-8ece82e4dcef6b7dd097350890e27b593ec079b1.tar.gz
Merge work:/my/mysql into donna.mysql.com:/home/my/bk/mysql
Docs/manual.texi: Auto merged
Diffstat (limited to 'client')
-rw-r--r--client/mysqltest.c882
1 files changed, 875 insertions, 7 deletions
diff --git a/client/mysqltest.c b/client/mysqltest.c
index 953f770240b..bb6011650e7 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -108,11 +108,10 @@ struct connection
char *name;
};
-typedef
- struct
- {
- int read_lines,current_line;
- } PARSER;
+typedef struct
+{
+ int read_lines,current_line;
+} PARSER;
PARSER parser;
MASTER_POS master_pos;
@@ -151,13 +150,14 @@ struct st_query
Q_DISCONNECT,Q_LET, Q_ECHO, Q_WHILE, Q_END_BLOCK,
Q_SYSTEM, Q_RESULT, Q_REQUIRE, Q_SAVE_MASTER_POS,
Q_SYNC_WITH_MASTER, Q_ERROR, Q_SEND, Q_REAP, Q_DIRTY_CLOSE,
+ Q_REPLACE,
Q_UNKNOWN, Q_COMMENT, Q_COMMENT_WITH_COMMAND} type;
};
const char *command_names[] = {
"connection", "query","connect","sleep","inc","dec","source","disconnect",
"let","echo","while","end","system","result", "require", "save_master_pos",
- "sync_with_master", "error", "send", "reap", "dirty_close", 0
+ "sync_with_master", "error", "send", "reap", "dirty_close", "replace", 0
};
TYPELIB command_typelib= {array_elements(command_names),"",
@@ -171,6 +171,30 @@ void reject_dump(const char* record_file, char* buf, int size);
int close_connection(struct st_query* q);
VAR* var_get(char* var_name, char* var_name_end, int raw);
+/* Definitions for replace */
+
+typedef struct st_pointer_array { /* when using array-strings */
+ TYPELIB typelib; /* Pointer to strings */
+ byte *str; /* Strings is here */
+ int7 *flag; /* Flag about each var. */
+ uint array_allocs,max_count,length,max_length;
+} POINTER_ARRAY;
+
+struct st_replace;
+struct st_replace *init_replace(my_string *from, my_string *to, uint count,
+ my_string word_end_chars);
+uint replace_strings(struct st_replace *rep, my_string *start,
+ uint *max_length, my_string from);
+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);
+static void free_replace_buffer(void);
+
+struct st_replace *glob_replace;
+static char *out_buff;
+static uint out_length;
+
+
static void close_cons()
{
DBUG_ENTER("close_cons");
@@ -610,7 +634,6 @@ static void get_ints(uint *to,struct st_query* q)
long val;
DBUG_ENTER("get_ints");
- while (*p && isspace(*p)) p++;
if (!*p)
die("Missing argument in %s\n", q->query);
@@ -624,6 +647,123 @@ static void get_ints(uint *to,struct st_query* q)
DBUG_VOID_RETURN;
}
+/*
+ Get a string; Return ptr to end of string
+ Strings may be surrounded by " or '
+*/
+
+
+static void get_string(char **to_ptr, char **from_ptr,
+ struct st_query* q)
+{
+ reg1 char c,sep;
+ char *to= *to_ptr, *from= *from_ptr;
+ DBUG_ENTER("get_string");
+
+ /* Find separator */
+ if (*from == '"' || *from == '\'')
+ sep= *from++;
+ else
+ sep=' '; /* Separated with space */
+
+ for ( ; (c=*from) ; from++)
+ {
+ if (c == '\\' && from[1])
+ { /* Escaped character */
+ /* We can't translate \0 -> ASCII 0 as replace can't handle ASCII 0 */
+ switch (*++from) {
+ case 'n':
+ *to++= '\n';
+ break;
+ case 't':
+ *to++= '\t';
+ break;
+ case 'r':
+ *to++ = '\r';
+ break;
+ case 'b':
+ *to++ = '\b';
+ break;
+ case 'Z': /* ^Z must be escaped on Win32 */
+ *to++='\032';
+ break;
+ default:
+ *to++ = *from;
+ break;
+ }
+ }
+ else if (c == sep)
+ {
+ if (c == ' ' || c != *++from)
+ break; /* Found end of string */
+ *to++=c; /* Copy duplicated separator */
+ }
+ else
+ *to++=c;
+ }
+ if (*from != ' ' && *from)
+ die("Wrong string argument in %s\n", q->query);
+
+ while (isspace(*from)) /* Point to next string */
+ from++;
+
+ *to++ =0; /* End of string marker */
+ *to_ptr= to;
+ *from_ptr= from;
+}
+
+
+/*
+ Get arguments for replace. The syntax is:
+ replace from to [from to ...]
+ Where each argument may be quoted with ' or "
+*/
+
+static void get_replace(struct st_query *q)
+{
+ uint i;
+ char *from=q->first_argument;
+ char *buff=my_malloc(strlen(from),MYF(MY_WME | MY_FAE));
+ char word_end_chars[256],*pos;
+ POINTER_ARRAY to_array,from_array;
+ DBUG_ENTER("get_replace");
+
+ bzero((char*) &to_array,sizeof(to_array));
+ bzero((char*) &from_array,sizeof(from_array));
+
+ if (!*from)
+ die("Missing argument in %s\n", q->query);
+ while (*from)
+ {
+ char *to=buff;
+ get_string(&buff, &from, q);
+ if (!*from)
+ die("Wrong number of arguments in %s\n", q->query);
+ insert_pointer_name(&from_array,to);
+ to=buff;
+ get_string(&buff, &from, q);
+ insert_pointer_name(&to_array,to);
+ }
+ for (i=1,pos=word_end_chars ; i < 256 ; i++)
+ if (isspace(i))
+ *pos++=i;
+ if (!(glob_replace=init_replace((char**) from_array.typelib.type_names,
+ (char**) to_array.typelib.type_names,
+ (uint) from_array.typelib.count,
+ word_end_chars)) ||
+ initialize_replace_buffer())
+ die("Can't initialize replace from %s\n", q->query);
+ free_pointer_array(&from_array);
+ free_pointer_array(&to_array);
+ my_free(buff, MYF(0));
+}
+
+void free_replace()
+{
+ my_free((char*) glob_replace,MYF(0));
+ free_replace_buffer();
+}
+
int select_connection(struct st_query* q)
{
@@ -845,6 +985,7 @@ int safe_copy_unescape(char* dest, char* src, int size)
return (p_dest - dest);
}
+
int read_line(char* buf, int size)
{
int c;
@@ -1340,11 +1481,20 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags)
if (i)
dynstr_append_mem(ds, "\t", 1);
+ if (glob_replace)
+ {
+ len=(int) replace_strings(glob_replace, &out_buff, &out_length, val);
+ if (len == -1)
+ die("Out of memory in replace\n");
+ val=out_buff;
+ }
dynstr_append_mem(ds, val, len);
}
dynstr_append_mem(ds, "\n", 1);
}
+ if (glob_replace)
+ free_replace();
if (record)
{
@@ -1481,6 +1631,9 @@ int main(int argc, char** argv)
get_file_name(save_file,q);
require_file=1;
break;
+ case Q_REPLACE:
+ get_replace(q);
+ break;
case Q_SAVE_MASTER_POS: do_save_master_pos(q); break;
case Q_SYNC_WITH_MASTER: do_sync_with_master(q); break;
case Q_COMMENT: /* Ignore row */
@@ -1523,3 +1676,718 @@ int main(int argc, char** argv)
exit(error);
return error;
}
+
+
+/****************************************************************************
+* Handle replacement of strings
+****************************************************************************/
+
+#define PC_MALLOC 256 /* Bytes for pointers */
+#define PS_MALLOC 512 /* Bytes for data */
+
+#define SPACE_CHAR 256
+#define START_OF_LINE 257
+#define END_OF_LINE 258
+#define LAST_CHAR_CODE 259
+
+typedef struct st_replace {
+ bool found;
+ struct st_replace *next[256];
+} REPLACE;
+
+typedef struct st_replace_found {
+ bool found;
+ char *replace_string;
+ uint to_offset;
+ int from_offset;
+} REPLACE_STRING;
+
+#ifndef WORD_BIT
+#define WORD_BIT (8*sizeof(uint))
+#endif
+
+
+static int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name)
+{
+ uint i,length,old_count;
+ byte *new_pos;
+ const char **new_array;
+ DBUG_ENTER("insert_pointer_name");
+
+ if (! pa->typelib.count)
+ {
+ if (!(pa->typelib.type_names=(const char **)
+ my_malloc(((PC_MALLOC-MALLOC_OVERHEAD)/
+ (sizeof(my_string)+sizeof(*pa->flag))*
+ (sizeof(my_string)+sizeof(*pa->flag))),MYF(MY_WME))))
+ DBUG_RETURN(-1);
+ if (!(pa->str= (byte*) my_malloc((uint) (PS_MALLOC-MALLOC_OVERHEAD),
+ MYF(MY_WME))))
+ {
+ my_free((gptr) pa->typelib.type_names,MYF(0));
+ DBUG_RETURN (-1);
+ }
+ pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(sizeof(byte*)+
+ sizeof(*pa->flag));
+ pa->flag= (int7*) (pa->typelib.type_names+pa->max_count);
+ pa->length=0;
+ pa->max_length=PS_MALLOC-MALLOC_OVERHEAD;
+ pa->array_allocs=1;
+ }
+ length=(uint) strlen(name)+1;
+ if (pa->length+length >= pa->max_length)
+ {
+ if (!(new_pos= (byte*) my_realloc((gptr) pa->str,
+ (uint) (pa->max_length+PS_MALLOC),
+ MYF(MY_WME))))
+ DBUG_RETURN(1);
+ if (new_pos != pa->str)
+ {
+ my_ptrdiff_t diff=PTR_BYTE_DIFF(new_pos,pa->str);
+ for (i=0 ; i < pa->typelib.count ; i++)
+ pa->typelib.type_names[i]= ADD_TO_PTR(pa->typelib.type_names[i],diff,
+ char*);
+ pa->str=new_pos;
+ }
+ pa->max_length+=PS_MALLOC;
+ }
+ if (pa->typelib.count >= pa->max_count-1)
+ {
+ int len;
+ pa->array_allocs++;
+ len=(PC_MALLOC*pa->array_allocs - MALLOC_OVERHEAD);
+ if (!(new_array=(const char **) my_realloc((gptr) pa->typelib.type_names,
+ (uint) len/
+ (sizeof(byte*)+sizeof(*pa->flag))*
+ (sizeof(byte*)+sizeof(*pa->flag)),
+ MYF(MY_WME))))
+ DBUG_RETURN(1);
+ pa->typelib.type_names=new_array;
+ old_count=pa->max_count;
+ pa->max_count=len/(sizeof(byte*) + sizeof(*pa->flag));
+ pa->flag= (int7*) (pa->typelib.type_names+pa->max_count);
+ memcpy((byte*) pa->flag,(my_string) (pa->typelib.type_names+old_count),
+ old_count*sizeof(*pa->flag));
+ }
+ pa->flag[pa->typelib.count]=0; /* Reset flag */
+ pa->typelib.type_names[pa->typelib.count++]= pa->str+pa->length;
+ pa->typelib.type_names[pa->typelib.count]= NullS; /* Put end-mark */
+ VOID(strmov(pa->str+pa->length,name));
+ pa->length+=length;
+ DBUG_RETURN(0);
+} /* insert_pointer_name */
+
+
+ /* free pointer array */
+
+void free_pointer_array(POINTER_ARRAY *pa)
+{
+ if (pa->typelib.count)
+ {
+ pa->typelib.count=0;
+ my_free((gptr) pa->typelib.type_names,MYF(0));
+ pa->typelib.type_names=0;
+ my_free((gptr) pa->str,MYF(0));
+ }
+ return;
+} /* free_pointer_array */
+
+
+ /* Code for replace rutines */
+
+#define SET_MALLOC_HUNC 64
+
+typedef struct st_rep_set {
+ uint *bits; /* Pointer to used sets */
+ short next[LAST_CHAR_CODE]; /* Pointer to next sets */
+ uint found_len; /* Best match to date */
+ int found_offset;
+ uint table_offset;
+ uint size_of_bits; /* For convinience */
+} REP_SET;
+
+typedef struct st_rep_sets {
+ uint count; /* Number of sets */
+ uint extra; /* Extra sets in buffer */
+ uint invisible; /* Sets not chown */
+ uint size_of_bits;
+ REP_SET *set,*set_buffer;
+ uint *bit_buffer;
+} REP_SETS;
+
+typedef struct st_found_set {
+ uint table_offset;
+ int found_offset;
+} FOUND_SET;
+
+typedef struct st_follow {
+ int chr;
+ uint table_offset;
+ uint len;
+} FOLLOWS;
+
+
+static int init_sets(REP_SETS *sets,uint states);
+static REP_SET *make_new_set(REP_SETS *sets);
+static void make_sets_invisible(REP_SETS *sets);
+static void free_last_set(REP_SETS *sets);
+static void free_sets(REP_SETS *sets);
+static void set_bit(REP_SET *set, uint bit);
+static void clear_bit(REP_SET *set, uint bit);
+static void or_bits(REP_SET *to,REP_SET *from);
+static void copy_bits(REP_SET *to,REP_SET *from);
+static int cmp_bits(REP_SET *set1,REP_SET *set2);
+static int get_next_bit(REP_SET *set,uint lastpos);
+static int find_set(REP_SETS *sets,REP_SET *find);
+static int find_found(FOUND_SET *found_set,uint table_offset,
+ int found_offset);
+static uint start_at_word(my_string pos);
+static uint end_of_word(my_string pos);
+static uint replace_len(my_string pos);
+
+static uint found_sets=0;
+
+
+ /* Init a replace structure for further calls */
+
+REPLACE *init_replace(my_string *from, my_string *to,uint count,
+ my_string word_end_chars)
+{
+ uint i,j,states,set_nr,len,result_len,max_length,found_end,bits_set,bit_nr;
+ int used_sets,chr,default_state;
+ char used_chars[LAST_CHAR_CODE],is_word_end[256];
+ my_string pos,to_pos,*to_array;
+ REP_SETS sets;
+ REP_SET *set,*start_states,*word_states,*new_set;
+ FOLLOWS *follow,*follow_ptr;
+ REPLACE *replace;
+ FOUND_SET *found_set;
+ REPLACE_STRING *rep_str;
+ DBUG_ENTER("init_replace");
+
+ /* Count number of states */
+ for (i=result_len=max_length=0 , states=2 ; i < count ; i++)
+ {
+ len=replace_len(from[i]);
+ if (!len)
+ {
+ errno=EINVAL;
+ my_message(0,"No to-string for last from-string",MYF(ME_BELL));
+ DBUG_RETURN(0);
+ }
+ states+=len+1;
+ result_len+=(uint) strlen(to[i])+1;
+ if (len > max_length)
+ max_length=len;
+ }
+ bzero((char*) is_word_end,sizeof(is_word_end));
+ for (i=0 ; word_end_chars[i] ; i++)
+ is_word_end[(uchar) word_end_chars[i]]=1;
+
+ if (init_sets(&sets,states))
+ DBUG_RETURN(0);
+ found_sets=0;
+ if (!(found_set= (FOUND_SET*) my_malloc(sizeof(FOUND_SET)*max_length*count,
+ MYF(MY_WME))))
+ {
+ free_sets(&sets);
+ DBUG_RETURN(0);
+ }
+ VOID(make_new_set(&sets)); /* Set starting set */
+ make_sets_invisible(&sets); /* Hide previus sets */
+ used_sets=-1;
+ word_states=make_new_set(&sets); /* Start of new word */
+ start_states=make_new_set(&sets); /* This is first state */
+ if (!(follow=(FOLLOWS*) my_malloc((states+2)*sizeof(FOLLOWS),MYF(MY_WME))))
+ {
+ free_sets(&sets);
+ my_free((gptr) found_set,MYF(0));
+ DBUG_RETURN(0);
+ }
+
+ /* Init follow_ptr[] */
+ for (i=0, states=1, follow_ptr=follow+1 ; i < count ; i++)
+ {
+ if (from[i][0] == '\\' && from[i][1] == '^')
+ {
+ set_bit(start_states,states+1);
+ if (!from[i][2])
+ {
+ start_states->table_offset=i;
+ start_states->found_offset=1;
+ }
+ }
+ else if (from[i][0] == '\\' && from[i][1] == '$')
+ {
+ set_bit(start_states,states);
+ set_bit(word_states,states);
+ if (!from[i][2] && start_states->table_offset == (uint) ~0)
+ {
+ start_states->table_offset=i;
+ start_states->found_offset=0;
+ }
+ }
+ else
+ {
+ set_bit(word_states,states);
+ if (from[i][0] == '\\' && (from[i][1] == 'b' && from[i][2]))
+ set_bit(start_states,states+1);
+ else
+ set_bit(start_states,states);
+ }
+ for (pos=from[i], len=0; *pos ; pos++)
+ {
+ if (*pos == '\\' && *(pos+1))
+ {
+ pos++;
+ switch (*pos) {
+ case 'b':
+ follow_ptr->chr = SPACE_CHAR;
+ break;
+ case '^':
+ follow_ptr->chr = START_OF_LINE;
+ break;
+ case '$':
+ follow_ptr->chr = END_OF_LINE;
+ break;
+ case 'r':
+ follow_ptr->chr = '\r';
+ break;
+ case 't':
+ follow_ptr->chr = '\t';
+ break;
+ case 'v':
+ follow_ptr->chr = '\v';
+ break;
+ default:
+ follow_ptr->chr = (uchar) *pos;
+ break;
+ }
+ }
+ else
+ follow_ptr->chr= (uchar) *pos;
+ follow_ptr->table_offset=i;
+ follow_ptr->len= ++len;
+ follow_ptr++;
+ }
+ follow_ptr->chr=0;
+ follow_ptr->table_offset=i;
+ follow_ptr->len=len;
+ follow_ptr++;
+ states+=(uint) len+1;
+ }
+
+
+ for (set_nr=0,pos=0 ; set_nr < sets.count ; set_nr++)
+ {
+ set=sets.set+set_nr;
+ default_state= 0; /* Start from beginning */
+
+ /* If end of found-string not found or start-set with current set */
+
+ for (i= (uint) ~0; (i=get_next_bit(set,i)) ;)
+ {
+ if (!follow[i].chr)
+ {
+ if (! default_state)
+ default_state= find_found(found_set,set->table_offset,
+ set->found_offset+1);
+ }
+ }
+ copy_bits(sets.set+used_sets,set); /* Save set for changes */
+ if (!default_state)
+ or_bits(sets.set+used_sets,sets.set); /* Can restart from start */
+
+ /* Find all chars that follows current sets */
+ bzero((char*) used_chars,sizeof(used_chars));
+ for (i= (uint) ~0; (i=get_next_bit(sets.set+used_sets,i)) ;)
+ {
+ used_chars[follow[i].chr]=1;
+ if ((follow[i].chr == SPACE_CHAR && !follow[i+1].chr &&
+ follow[i].len > 1) || follow[i].chr == END_OF_LINE)
+ used_chars[0]=1;
+ }
+
+ /* Mark word_chars used if \b is in state */
+ if (used_chars[SPACE_CHAR])
+ for (pos= word_end_chars ; *pos ; pos++)
+ used_chars[(int) (uchar) *pos] = 1;
+
+ /* Handle other used characters */
+ for (chr= 0 ; chr < 256 ; chr++)
+ {
+ if (! used_chars[chr])
+ set->next[chr]= chr ? default_state : -1;
+ else
+ {
+ new_set=make_new_set(&sets);
+ set=sets.set+set_nr; /* if realloc */
+ new_set->table_offset=set->table_offset;
+ new_set->found_len=set->found_len;
+ new_set->found_offset=set->found_offset+1;
+ found_end=0;
+
+ for (i= (uint) ~0 ; (i=get_next_bit(sets.set+used_sets,i)) ; )
+ {
+ if (!follow[i].chr || follow[i].chr == chr ||
+ (follow[i].chr == SPACE_CHAR &&
+ (is_word_end[chr] ||
+ (!chr && follow[i].len > 1 && ! follow[i+1].chr))) ||
+ (follow[i].chr == END_OF_LINE && ! chr))
+ {
+ if ((! chr || (follow[i].chr && !follow[i+1].chr)) &&
+ follow[i].len > found_end)
+ found_end=follow[i].len;
+ if (chr && follow[i].chr)
+ set_bit(new_set,i+1); /* To next set */
+ else
+ set_bit(new_set,i);
+ }
+ }
+ if (found_end)
+ {
+ new_set->found_len=0; /* Set for testing if first */
+ bits_set=0;
+ for (i= (uint) ~0; (i=get_next_bit(new_set,i)) ;)
+ {
+ if ((follow[i].chr == SPACE_CHAR ||
+ follow[i].chr == END_OF_LINE) && ! chr)
+ bit_nr=i+1;
+ else
+ bit_nr=i;
+ if (follow[bit_nr-1].len < found_end ||
+ (new_set->found_len &&
+ (chr == 0 || !follow[bit_nr].chr)))
+ clear_bit(new_set,i);
+ else
+ {
+ if (chr == 0 || !follow[bit_nr].chr)
+ { /* best match */
+ new_set->table_offset=follow[bit_nr].table_offset;
+ if (chr || (follow[i].chr == SPACE_CHAR ||
+ follow[i].chr == END_OF_LINE))
+ new_set->found_offset=found_end; /* New match */
+ new_set->found_len=found_end;
+ }
+ bits_set++;
+ }
+ }
+ if (bits_set == 1)
+ {
+ set->next[chr] = find_found(found_set,
+ new_set->table_offset,
+ new_set->found_offset);
+ free_last_set(&sets);
+ }
+ else
+ set->next[chr] = find_set(&sets,new_set);
+ }
+ else
+ set->next[chr] = find_set(&sets,new_set);
+ }
+ }
+ }
+
+ /* Alloc replace structure for the replace-state-machine */
+
+ if ((replace=(REPLACE*) my_malloc(sizeof(REPLACE)*(sets.count)+
+ sizeof(REPLACE_STRING)*(found_sets+1)+
+ sizeof(my_string)*count+result_len,
+ MYF(MY_WME | MY_ZEROFILL))))
+ {
+ rep_str=(REPLACE_STRING*) (replace+sets.count);
+ to_array=(my_string*) (rep_str+found_sets+1);
+ to_pos=(my_string) (to_array+count);
+ for (i=0 ; i < count ; i++)
+ {
+ to_array[i]=to_pos;
+ to_pos=strmov(to_pos,to[i])+1;
+ }
+ rep_str[0].found=1;
+ rep_str[0].replace_string=0;
+ for (i=1 ; i <= found_sets ; i++)
+ {
+ pos=from[found_set[i-1].table_offset];
+ rep_str[i].found= !bcmp(pos,"\\^",3) ? 2 : 1;
+ rep_str[i].replace_string=to_array[found_set[i-1].table_offset];
+ rep_str[i].to_offset=found_set[i-1].found_offset-start_at_word(pos);
+ rep_str[i].from_offset=found_set[i-1].found_offset-replace_len(pos)+
+ end_of_word(pos);
+ }
+ for (i=0 ; i < sets.count ; i++)
+ {
+ for (j=0 ; j < 256 ; j++)
+ if (sets.set[i].next[j] >= 0)
+ replace[i].next[j]=replace+sets.set[i].next[j];
+ else
+ replace[i].next[j]=(REPLACE*) (rep_str+(-sets.set[i].next[j]-1));
+ }
+ }
+ my_free((gptr) follow,MYF(0));
+ free_sets(&sets);
+ my_free((gptr) found_set,MYF(0));
+ DBUG_PRINT("exit",("Replace table has %d states",sets.count));
+ DBUG_RETURN(replace);
+}
+
+
+static int init_sets(REP_SETS *sets,uint states)
+{
+ bzero((char*) sets,sizeof(*sets));
+ sets->size_of_bits=((states+7)/8);
+ if (!(sets->set_buffer=(REP_SET*) my_malloc(sizeof(REP_SET)*SET_MALLOC_HUNC,
+ MYF(MY_WME))))
+ return 1;
+ if (!(sets->bit_buffer=(uint*) my_malloc(sizeof(uint)*sets->size_of_bits*
+ SET_MALLOC_HUNC,MYF(MY_WME))))
+ {
+ my_free((gptr) sets->set,MYF(0));
+ return 1;
+ }
+ return 0;
+}
+
+ /* Make help sets invisible for nicer codeing */
+
+static void make_sets_invisible(REP_SETS *sets)
+{
+ sets->invisible=sets->count;
+ sets->set+=sets->count;
+ sets->count=0;
+}
+
+static REP_SET *make_new_set(REP_SETS *sets)
+{
+ uint i,count,*bit_buffer;
+ REP_SET *set;
+ if (sets->extra)
+ {
+ sets->extra--;
+ set=sets->set+ sets->count++;
+ bzero((char*) set->bits,sizeof(uint)*sets->size_of_bits);
+ bzero((char*) &set->next[0],sizeof(set->next[0])*LAST_CHAR_CODE);
+ set->found_offset=0;
+ set->found_len=0;
+ set->table_offset= (uint) ~0;
+ set->size_of_bits=sets->size_of_bits;
+ return set;
+ }
+ count=sets->count+sets->invisible+SET_MALLOC_HUNC;
+ if (!(set=(REP_SET*) my_realloc((gptr) sets->set_buffer,
+ sizeof(REP_SET)*count,
+ MYF(MY_WME))))
+ return 0;
+ sets->set_buffer=set;
+ sets->set=set+sets->invisible;
+ if (!(bit_buffer=(uint*) my_realloc((gptr) sets->bit_buffer,
+ (sizeof(uint)*sets->size_of_bits)*count,
+ MYF(MY_WME))))
+ return 0;
+ sets->bit_buffer=bit_buffer;
+ for (i=0 ; i < count ; i++)
+ {
+ sets->set_buffer[i].bits=bit_buffer;
+ bit_buffer+=sets->size_of_bits;
+ }
+ sets->extra=SET_MALLOC_HUNC;
+ return make_new_set(sets);
+}
+
+static void free_last_set(REP_SETS *sets)
+{
+ sets->count--;
+ sets->extra++;
+ return;
+}
+
+static void free_sets(REP_SETS *sets)
+{
+ my_free((gptr)sets->set_buffer,MYF(0));
+ my_free((gptr)sets->bit_buffer,MYF(0));
+ return;
+}
+
+static void set_bit(REP_SET *set, uint bit)
+{
+ set->bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT);
+ return;
+}
+
+static void clear_bit(REP_SET *set, uint bit)
+{
+ set->bits[bit / WORD_BIT] &= ~ (1 << (bit % WORD_BIT));
+ return;
+}
+
+
+static void or_bits(REP_SET *to,REP_SET *from)
+{
+ reg1 uint i;
+ for (i=0 ; i < to->size_of_bits ; i++)
+ to->bits[i]|=from->bits[i];
+ return;
+}
+
+static void copy_bits(REP_SET *to,REP_SET *from)
+{
+ memcpy((byte*) to->bits,(byte*) from->bits,
+ (size_t) (sizeof(uint) * to->size_of_bits));
+}
+
+static int cmp_bits(REP_SET *set1,REP_SET *set2)
+{
+ return bcmp((byte*) set1->bits,(byte*) set2->bits,
+ sizeof(uint) * set1->size_of_bits);
+}
+
+
+ /* Get next set bit from set. */
+
+static int get_next_bit(REP_SET *set,uint lastpos)
+{
+ uint pos,*start,*end,bits;
+
+ start=set->bits+ ((lastpos+1) / WORD_BIT);
+ end=set->bits + set->size_of_bits;
+ bits=start[0] & ~((1 << ((lastpos+1) % WORD_BIT)) -1);
+
+ while (! bits && ++start < end)
+ bits=start[0];
+ if (!bits)
+ return 0;
+ pos=(uint) (start-set->bits)*WORD_BIT;
+ while (! (bits & 1))
+ {
+ bits>>=1;
+ pos++;
+ }
+ return pos;
+}
+
+ /* find if there is a same set in sets. If there is, use it and
+ free given set, else put in given set in sets and return it's
+ position */
+
+static int find_set(REP_SETS *sets,REP_SET *find)
+{
+ uint i;
+ for (i=0 ; i < sets->count-1 ; i++)
+ {
+ if (!cmp_bits(sets->set+i,find))
+ {
+ free_last_set(sets);
+ return i;
+ }
+ }
+ return i; /* return new postion */
+}
+
+ /* find if there is a found_set with same table_offset & found_offset
+ If there is return offset to it, else add new offset and return pos.
+ Pos returned is -offset-2 in found_set_structure because it's is
+ saved in set->next and set->next[] >= 0 points to next set and
+ set->next[] == -1 is reserved for end without replaces.
+ */
+
+static int find_found(FOUND_SET *found_set,uint table_offset, int found_offset)
+{
+ int i;
+ for (i=0 ; (uint) i < found_sets ; i++)
+ if (found_set[i].table_offset == table_offset &&
+ found_set[i].found_offset == found_offset)
+ return -i-2;
+ found_set[i].table_offset=table_offset;
+ found_set[i].found_offset=found_offset;
+ found_sets++;
+ return -i-2; /* return new postion */
+}
+
+ /* Return 1 if regexp starts with \b or ends with \b*/
+
+static uint start_at_word(my_string pos)
+{
+ return (((!bcmp(pos,"\\b",2) && pos[2]) || !bcmp(pos,"\\^",2)) ? 1 : 0);
+}
+
+static uint end_of_word(my_string pos)
+{
+ my_string end=strend(pos);
+ return ((end > pos+2 && !bcmp(end-2,"\\b",2)) ||
+ (end >= pos+2 && !bcmp(end-2,"\\$",2))) ?
+ 1 : 0;
+}
+
+
+static uint replace_len(my_string str)
+{
+ uint len=0;
+ while (*str)
+ {
+ if (str[0] == '\\' && str[1])
+ str++;
+ str++;
+ len++;
+ }
+ return len;
+}
+
+
+ /* Replace strings; Return length of result string */
+
+uint replace_strings(REPLACE *rep, my_string *start,uint *max_length,
+ my_string from)
+{
+ reg1 REPLACE *rep_pos;
+ reg2 REPLACE_STRING *rep_str;
+ my_string to,end,pos,new;
+
+ end=(to= *start) + *max_length-1;
+ rep_pos=rep+1;
+ for(;;)
+ {
+ while (!rep_pos->found)
+ {
+ rep_pos= rep_pos->next[(uchar) *from];
+ if (to == end)
+ {
+ (*max_length)+=8192;
+ if (!(new=my_realloc(*start,*max_length,MYF(MY_WME))))
+ return (uint) -1;
+ to=new+(to - *start);
+ end=(*start=new)+ *max_length-1;
+ }
+ *to++= *from++;
+ }
+ if (!(rep_str = ((REPLACE_STRING*) rep_pos))->replace_string)
+ return (uint) (to - *start)-1;
+ to-=rep_str->to_offset;
+ for (pos=rep_str->replace_string; *pos ; pos++)
+ {
+ if (to == end)
+ {
+ (*max_length)*=2;
+ if (!(new=my_realloc(*start,*max_length,MYF(MY_WME))))
+ return (uint) -1;
+ to=new+(to - *start);
+ end=(*start=new)+ *max_length-1;
+ }
+ *to++= *pos;
+ }
+ if (!*(from-=rep_str->from_offset) && rep_pos->found != 2)
+ return (uint) (to - *start);
+ rep_pos=rep;
+ }
+}
+
+static int initialize_replace_buffer(void)
+{
+ out_length=8192;
+ if (!(out_buff=my_malloc(out_length,MYF(MY_WME))))
+ return(1);
+ return 0;
+}
+
+static void free_replace_buffer(void)
+{
+ my_free(out_buff,MYF(MY_WME));
+}