replace.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:28k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.    
  3.    This library is free software; you can redistribute it and/or
  4.    modify it under the terms of the GNU Library General Public
  5.    License as published by the Free Software Foundation; either
  6.    version 2 of the License, or (at your option) any later version.
  7.    
  8.    This library is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11.    Library General Public License for more details.
  12.    
  13.    You should have received a copy of the GNU Library General Public
  14.    License along with this library; if not, write to the Free
  15.    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  16.    MA 02111-1307, USA */
  17. /* Replace strings in textfile
  18.   This program replace strings in a file or on stdin/stdout.
  19.   It accepts a list of from-strings and to-strings and replaces all
  20.   occurents of from-strings to to-strings.
  21.   The first occurents of a found string is matched. If there are more than
  22.   one possibly replace the longer from-string is replaced.
  23.   Special characters in from string:
  24.   ^    Match start of line.
  25.   $ Match end of line.
  26.   b Match space-character, start of line or end of line.
  27.         For end b the next replace starts locking at the end space-character.
  28.         An b alone or in a string matches only a space-character.
  29.   r, t, v as in C.
  30.   The programs make a DFA-state-machine of the strings and the speed isn't
  31.   dependent on the count of replace-strings (only of the number of replaces).
  32.   A line is assumed ending with n or .
  33.   There are no limit exept memory on length of strings.
  34.   Written by Monty.
  35.   fill_buffer_retaining() is taken from gnu-grep and modified.
  36. */
  37. #define DONT_USE_RAID
  38. #include <global.h>
  39. #include <m_ctype.h>
  40. #include <my_sys.h>
  41. #include <m_string.h>
  42. #include <errno.h>
  43. #define PC_MALLOC 256 /* Bytes for pointers */
  44. #define PS_MALLOC 512 /* Bytes for data */
  45. typedef struct st_pointer_array { /* when using array-strings */
  46.   TYPELIB typelib; /* Pointer to strings */
  47.   byte *str; /* Strings is here */
  48.   int7 *flag; /* Flag about each var. */
  49.   uint  array_allocs,max_count,length,max_length;
  50. } POINTER_ARRAY;
  51. #define SPACE_CHAR 256
  52. #define START_OF_LINE 257
  53. #define END_OF_LINE 258
  54. #define LAST_CHAR_CODE 259
  55. typedef struct st_replace {
  56.   bool   found;
  57.   struct st_replace *next[256];
  58. } REPLACE;
  59. typedef struct st_replace_found {
  60.   bool found;
  61.   char *replace_string;
  62.   uint to_offset;
  63.   int from_offset;
  64. } REPLACE_STRING;
  65. #ifndef WORD_BIT
  66. #define WORD_BIT (8*sizeof(uint))
  67. #endif
  68. /* functions defined in this file */
  69. extern int main(int argc,char * *argv);
  70. static int static_get_options(int *argc,char * * *argv);
  71. static int get_replace_strings(int *argc,char * * *argv,
  72.    POINTER_ARRAY *from_array,
  73.    POINTER_ARRAY *to_array);
  74. int insert_pointer_name(POINTER_ARRAY *pa, my_string name);
  75. void free_pointer_array(POINTER_ARRAY *pa);
  76. static int convert_pipe(REPLACE *,FILE *,FILE *);
  77. static int convert_file(REPLACE *, my_string);
  78. REPLACE *init_replace(my_string *from, my_string *to,uint count, my_string
  79.       word_end_chars);
  80. uint replace_strings(REPLACE *rep, my_string *start,uint *max_length,
  81.      my_string from);
  82. static int initialize_buffer(void);
  83. static void reset_buffer(void);
  84. static void free_buffer(void);
  85. static int silent=0,verbose=0,updated=0;
  86. /* The main program */
  87. int main(argc,argv)
  88. int argc;
  89. char *argv[];
  90. {
  91.   int i,error;
  92.   char word_end_chars[256],*pos;
  93.   POINTER_ARRAY from,to;
  94.   REPLACE *replace;
  95.   MY_INIT(argv[0]);
  96.   if (static_get_options(&argc,&argv))
  97.     exit(1);
  98.   if (get_replace_strings(&argc,&argv,&from,&to))
  99.     exit(1);
  100.   for (i=1,pos=word_end_chars ; i < 256 ; i++)
  101.     if (isspace(i))
  102.       *pos++=i;
  103.   *pos=0;
  104.   if (!(replace=init_replace((char**) from.typelib.type_names,
  105.      (char**) to.typelib.type_names,
  106.      (uint) from.typelib.count,word_end_chars)))
  107.     exit(1);
  108.   free_pointer_array(&from);
  109.   free_pointer_array(&to);
  110.   if (initialize_buffer())
  111.     return 1;
  112.   error=0;
  113.   if (argc == 0)
  114.     error=convert_pipe(replace,stdin,stdout);
  115.   else
  116.   {
  117.     while (argc--)
  118.     {
  119.       error=convert_file(replace,*(argv++));
  120.     }
  121.   }
  122.   free_buffer();
  123.   my_end(verbose ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
  124.   exit(error ? 2 : 0);
  125.   return 0; /* No compiler warning */
  126. } /* main */
  127. /* reads options */
  128. /* Initiates DEBUG - but no debugging here ! */
  129. static int static_get_options(argc,argv)
  130. register int *argc;
  131. register char **argv[];
  132. {
  133.   int help,version,opt;
  134.   char *pos;
  135.   silent=verbose=help=0;
  136.   while (--*argc > 0 && *(pos = *(++*argv)) == '-' && pos[1] != '-') {
  137.     while (*++pos)
  138.     {
  139.       version=0;
  140.       switch((opt= *pos)) {
  141.       case 's':
  142. silent=1;
  143. break;
  144.       case 'v':
  145. verbose=1;
  146. break;
  147.       case '#':
  148. DBUG_PUSH (++pos);
  149. pos= (char*) " "; /* Skipp rest of arguments */
  150. break;
  151.       case 'V':
  152. version=1;
  153.       case 'I':
  154.       case '?':
  155. help=1; /* Help text written */
  156. printf("%s  Ver 1.3 for %s at %sn",my_progname,SYSTEM_TYPE,
  157.        MACHINE_TYPE);
  158. if (version)
  159.   break;
  160. puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,nand you are welcome to modify and redistribute it under the GPL licensen");
  161. puts("This program replace strings in a file or on stdin/stdout.n"
  162.      "It accepts a list of from-strings and to-strings and replacesn"
  163.      "all occurents of from-strings to to-strings.n"
  164.      "The first occurents of a found string is matched. Longer matchesn"
  165.      "are prefered before shorter matches.nn"
  166.      "Special characters in from string:n"
  167.      "  \^      Match start of line.n"
  168.      "  \$      Match end of line.n"
  169.      "  \b      Match space-character, start of line or end of line.n"
  170.      "          For a end \b the next replace starts locking at the endn"
  171.      "          space-character. A \b alone in a string matches only an"
  172.      "          space-character.n");
  173.   printf("Usage: %s [-?svIV] from to from to ... -- [files]n", my_progname);
  174. puts("or");
  175.   printf("Usage: %s [-?svIV] from to from to ... < fromfile > tofilen", my_progname);
  176. puts("");
  177. puts("Options: -? or -I "Info"  -s "silent"      -v "verbose"");
  178. break;
  179.       default:
  180. fprintf(stderr,"illegal option: -%cn",*pos);
  181. break;
  182.       }
  183.     }
  184.   }
  185.   if (*argc == 0)
  186.   {
  187.     if (!help)
  188.       my_message(0,"No replace options given",MYF(ME_BELL));
  189.     exit(0); /* Don't use as pipe */
  190.   }
  191.   return(0);
  192. } /* static_get_options */
  193. static int get_replace_strings(argc,argv,from_array,to_array)
  194. register int *argc;
  195. register char **argv[];
  196. POINTER_ARRAY *from_array,*to_array;
  197. {
  198.   char *pos;
  199.   bzero((char*) from_array,sizeof(from_array[0]));
  200.   bzero((char*) to_array,sizeof(to_array[0]));
  201.   while (*argc > 0 && (*(pos = *(*argv)) != '-' || pos[1] != '-' || pos[2]))
  202.   {
  203.     insert_pointer_name(from_array,pos);
  204.     (*argc)--;
  205.     (*argv)++;
  206.     if (!*argc || !strcmp(**argv,"--"))
  207.     {
  208.       my_message(0,"No to-string for last from-string",MYF(ME_BELL));
  209.       return 1;
  210.     }
  211.     insert_pointer_name(to_array,**argv);
  212.     (*argc)--;
  213.     (*argv)++;
  214.   }
  215.   if (*argc)
  216.   { /* Skipp "--" argument */
  217.     (*argc)--;
  218.     (*argv)++;
  219.   }
  220.   return 0;
  221. }
  222. int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name)
  223. {
  224.   uint i,length,old_count;
  225.   byte *new_pos;
  226.   const char **new_array;
  227.   DBUG_ENTER("insert_pointer_name");
  228.   if (! pa->typelib.count)
  229.   {
  230.     if (!(pa->typelib.type_names=(const char **)
  231.   my_malloc(((PC_MALLOC-MALLOC_OVERHEAD)/
  232.      (sizeof(my_string)+sizeof(*pa->flag))*
  233.      (sizeof(my_string)+sizeof(*pa->flag))),MYF(MY_WME))))
  234.       DBUG_RETURN(-1);
  235.     if (!(pa->str= (byte*) my_malloc((uint) (PS_MALLOC-MALLOC_OVERHEAD),
  236.      MYF(MY_WME))))
  237.     {
  238.       my_free((gptr) pa->typelib.type_names,MYF(0));
  239.       DBUG_RETURN (-1);
  240.     }
  241.     pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(sizeof(byte*)+
  242.        sizeof(*pa->flag));
  243.     pa->flag= (int7*) (pa->typelib.type_names+pa->max_count);
  244.     pa->length=0;
  245.     pa->max_length=PS_MALLOC-MALLOC_OVERHEAD;
  246.     pa->array_allocs=1;
  247.   }
  248.   length=(uint) strlen(name)+1;
  249.   if (pa->length+length >= pa->max_length)
  250.   {
  251.     if (!(new_pos= (byte*) my_realloc((gptr) pa->str,
  252.       (uint) (pa->max_length+PS_MALLOC),
  253.       MYF(MY_WME))))
  254.       DBUG_RETURN(1);
  255.     if (new_pos != pa->str)
  256.     {
  257.       my_ptrdiff_t diff=PTR_BYTE_DIFF(new_pos,pa->str);
  258.       for (i=0 ; i < pa->typelib.count ; i++)
  259. pa->typelib.type_names[i]= ADD_TO_PTR(pa->typelib.type_names[i],diff,
  260.       char*);
  261.       pa->str=new_pos;
  262.     }
  263.     pa->max_length+=PS_MALLOC;
  264.   }
  265.   if (pa->typelib.count >= pa->max_count-1)
  266.   {
  267.     int len;
  268.     pa->array_allocs++;
  269.     len=(PC_MALLOC*pa->array_allocs - MALLOC_OVERHEAD);
  270.     if (!(new_array=(const char **) my_realloc((gptr) pa->typelib.type_names,
  271.        (uint) len/
  272.  (sizeof(byte*)+sizeof(*pa->flag))*
  273.  (sizeof(byte*)+sizeof(*pa->flag)),
  274.  MYF(MY_WME))))
  275.       DBUG_RETURN(1);
  276.     pa->typelib.type_names=new_array;
  277.     old_count=pa->max_count;
  278.     pa->max_count=len/(sizeof(byte*) + sizeof(*pa->flag));
  279.     pa->flag= (int7*) (pa->typelib.type_names+pa->max_count);
  280.     memcpy((byte*) pa->flag,(my_string) (pa->typelib.type_names+old_count),
  281.    old_count*sizeof(*pa->flag));
  282.   }
  283.   pa->flag[pa->typelib.count]=0; /* Reset flag */
  284.   pa->typelib.type_names[pa->typelib.count++]= pa->str+pa->length;
  285.   pa->typelib.type_names[pa->typelib.count]= NullS; /* Put end-mark */
  286.   VOID(strmov(pa->str+pa->length,name));
  287.   pa->length+=length;
  288.   DBUG_RETURN(0);
  289. } /* insert_pointer_name */
  290. /* free pointer array */
  291. void free_pointer_array(pa)
  292. reg1 POINTER_ARRAY *pa;
  293. {
  294.   if (pa->typelib.count)
  295.   {
  296.     pa->typelib.count=0;
  297.     my_free((gptr) pa->typelib.type_names,MYF(0));
  298.     pa->typelib.type_names=0;
  299.     my_free((gptr) pa->str,MYF(0));
  300.   }
  301.   return;
  302. } /* free_pointer_array */
  303. /* Code for replace rutines */
  304. #define SET_MALLOC_HUNC 64
  305. typedef struct st_rep_set {
  306.   uint  *bits; /* Pointer to used sets */
  307.   short next[LAST_CHAR_CODE]; /* Pointer to next sets */
  308.   uint found_len; /* Best match to date */
  309.   int found_offset;
  310.   uint  table_offset;
  311.   uint  size_of_bits; /* For convinience */
  312. } REP_SET;
  313. typedef struct st_rep_sets {
  314.   uint count; /* Number of sets */
  315.   uint extra; /* Extra sets in buffer */
  316.   uint invisible; /* Sets not chown */
  317.   uint size_of_bits;
  318.   REP_SET *set,*set_buffer;
  319.   uint *bit_buffer;
  320. } REP_SETS;
  321. typedef struct st_found_set {
  322.   uint table_offset;
  323.   int found_offset;
  324. } FOUND_SET;
  325. typedef struct st_follow {
  326.   int chr;
  327.   uint table_offset;
  328.   uint len;
  329. } FOLLOWS;
  330. static int init_sets(REP_SETS *sets,uint states);
  331. static REP_SET *make_new_set(REP_SETS *sets);
  332. static void make_sets_invisible(REP_SETS *sets);
  333. static void free_last_set(REP_SETS *sets);
  334. static void free_sets(REP_SETS *sets);
  335. static void set_bit(REP_SET *set, uint bit);
  336. static void clear_bit(REP_SET *set, uint bit);
  337. static void or_bits(REP_SET *to,REP_SET *from);
  338. static void copy_bits(REP_SET *to,REP_SET *from);
  339. static int cmp_bits(REP_SET *set1,REP_SET *set2);
  340. static int get_next_bit(REP_SET *set,uint lastpos);
  341. static int find_set(REP_SETS *sets,REP_SET *find);
  342. static int find_found(FOUND_SET *found_set,uint table_offset,
  343.   int found_offset);
  344. static uint start_at_word(my_string pos);
  345. static uint end_of_word(my_string pos);
  346. static uint replace_len(my_string pos);
  347. static uint found_sets=0;
  348. /* Init a replace structure for further calls */
  349. REPLACE *init_replace(my_string *from, my_string *to,uint count,
  350.       my_string word_end_chars)
  351. {
  352.   uint i,j,states,set_nr,len,result_len,max_length,found_end,bits_set,bit_nr;
  353.   int used_sets,chr,default_state;
  354.   char used_chars[LAST_CHAR_CODE],is_word_end[256];
  355.   my_string pos,to_pos,*to_array;
  356.   REP_SETS sets;
  357.   REP_SET *set,*start_states,*word_states,*new_set;
  358.   FOLLOWS *follow,*follow_ptr;
  359.   REPLACE *replace;
  360.   FOUND_SET *found_set;
  361.   REPLACE_STRING *rep_str;
  362.   DBUG_ENTER("init_replace");
  363.   /* Count number of states */
  364.   for (i=result_len=max_length=0 , states=2 ; i < count ; i++)
  365.   {
  366.     len=replace_len(from[i]);
  367.     if (!len)
  368.     {
  369.       errno=EINVAL;
  370.       my_message(0,"No to-string for last from-string",MYF(ME_BELL));
  371.       DBUG_RETURN(0);
  372.     }
  373.     states+=len+1;
  374.     result_len+=(uint) strlen(to[i])+1;
  375.     if (len > max_length)
  376.       max_length=len;
  377.   }
  378.   bzero((char*) is_word_end,sizeof(is_word_end));
  379.   for (i=0 ; word_end_chars[i] ; i++)
  380.     is_word_end[(uchar) word_end_chars[i]]=1;
  381.   if (init_sets(&sets,states))
  382.     DBUG_RETURN(0);
  383.   found_sets=0;
  384.   if (!(found_set= (FOUND_SET*) my_malloc(sizeof(FOUND_SET)*max_length*count,
  385.   MYF(MY_WME))))
  386.   {
  387.     free_sets(&sets);
  388.     DBUG_RETURN(0);
  389.   }
  390.   VOID(make_new_set(&sets)); /* Set starting set */
  391.   make_sets_invisible(&sets); /* Hide previus sets */
  392.   used_sets=-1;
  393.   word_states=make_new_set(&sets); /* Start of new word */
  394.   start_states=make_new_set(&sets); /* This is first state */
  395.   if (!(follow=(FOLLOWS*) my_malloc((states+2)*sizeof(FOLLOWS),MYF(MY_WME))))
  396.   {
  397.     free_sets(&sets);
  398.     my_free((gptr) found_set,MYF(0));
  399.     DBUG_RETURN(0);
  400.   }
  401. /* Init follow_ptr[] */
  402.   for (i=0, states=1, follow_ptr=follow+1 ; i < count ; i++)
  403.   {
  404.     if (from[i][0] == '\' && from[i][1] == '^')
  405.     {
  406.       set_bit(start_states,states+1);
  407.       if (!from[i][2])
  408.       {
  409. start_states->table_offset=i;
  410. start_states->found_offset=1;
  411.       }
  412.     }
  413.     else if (from[i][0] == '\' && from[i][1] == '$')
  414.     {
  415.       set_bit(start_states,states);
  416.       set_bit(word_states,states);
  417.       if (!from[i][2] && start_states->table_offset == (uint) ~0)
  418.       {
  419. start_states->table_offset=i;
  420. start_states->found_offset=0;
  421.       }
  422.     }
  423.     else
  424.     {
  425.       set_bit(word_states,states);
  426.       if (from[i][0] == '\' && (from[i][1] == 'b' && from[i][2]))
  427. set_bit(start_states,states+1);
  428.       else
  429. set_bit(start_states,states);
  430.     }
  431.     for (pos=from[i], len=0; *pos ; pos++)
  432.     {
  433.       if (*pos == '\' && *(pos+1))
  434.       {
  435. pos++;
  436. switch (*pos) {
  437. case 'b':
  438.   follow_ptr->chr = SPACE_CHAR;
  439.   break;
  440. case '^':
  441.   follow_ptr->chr = START_OF_LINE;
  442.   break;
  443. case '$':
  444.   follow_ptr->chr = END_OF_LINE;
  445.   break;
  446. case 'r':
  447.   follow_ptr->chr = 'r';
  448.   break;
  449. case 't':
  450.   follow_ptr->chr = 't';
  451.   break;
  452. case 'v':
  453.   follow_ptr->chr = 'v';
  454.   break;
  455. default:
  456.   follow_ptr->chr = (uchar) *pos;
  457.   break;
  458. }
  459.       }
  460.       else
  461. follow_ptr->chr= (uchar) *pos;
  462.       follow_ptr->table_offset=i;
  463.       follow_ptr->len= ++len;
  464.       follow_ptr++;
  465.     }
  466.     follow_ptr->chr=0;
  467.     follow_ptr->table_offset=i;
  468.     follow_ptr->len=len;
  469.     follow_ptr++;
  470.     states+=(uint) len+1;
  471.   }
  472.   for (set_nr=0,pos=0 ; set_nr < sets.count ; set_nr++)
  473.   {
  474.     set=sets.set+set_nr;
  475.     default_state= 0; /* Start from beginning */
  476.     /* If end of found-string not found or start-set with current set */
  477.     for (i= (uint) ~0; (i=get_next_bit(set,i)) ;)
  478.     {
  479.       if (!follow[i].chr)
  480.       {
  481. if (! default_state)
  482.   default_state= find_found(found_set,set->table_offset,
  483.     set->found_offset+1);
  484.       }
  485.     }
  486.     copy_bits(sets.set+used_sets,set); /* Save set for changes */
  487.     if (!default_state)
  488.       or_bits(sets.set+used_sets,sets.set); /* Can restart from start */
  489.     /* Find all chars that follows current sets */
  490.     bzero((char*) used_chars,sizeof(used_chars));
  491.     for (i= (uint) ~0; (i=get_next_bit(sets.set+used_sets,i)) ;)
  492.     {
  493.       used_chars[follow[i].chr]=1;
  494.       if ((follow[i].chr == SPACE_CHAR && !follow[i+1].chr &&
  495.    follow[i].len > 1) || follow[i].chr == END_OF_LINE)
  496. used_chars[0]=1;
  497.     }
  498.     /* Mark word_chars used if b is in state */
  499.     if (used_chars[SPACE_CHAR])
  500.       for (pos= word_end_chars ; *pos ; pos++)
  501. used_chars[(int) (uchar) *pos] = 1;
  502.     /* Handle other used characters */
  503.     for (chr= 0 ; chr < 256 ; chr++)
  504.     {
  505.       if (! used_chars[chr])
  506. set->next[chr]= chr ? default_state : -1;
  507.       else
  508.       {
  509. new_set=make_new_set(&sets);
  510. set=sets.set+set_nr; /* if realloc */
  511. new_set->table_offset=set->table_offset;
  512. new_set->found_len=set->found_len;
  513. new_set->found_offset=set->found_offset+1;
  514. found_end=0;
  515. for (i= (uint) ~0 ; (i=get_next_bit(sets.set+used_sets,i)) ; )
  516. {
  517.   if (!follow[i].chr || follow[i].chr == chr ||
  518.       (follow[i].chr == SPACE_CHAR &&
  519.        (is_word_end[chr] ||
  520. (!chr && follow[i].len > 1 && ! follow[i+1].chr))) ||
  521.       (follow[i].chr == END_OF_LINE && ! chr))
  522.   {
  523.     if ((! chr || (follow[i].chr && !follow[i+1].chr)) &&
  524. follow[i].len > found_end)
  525.       found_end=follow[i].len;
  526.     if (chr && follow[i].chr)
  527.       set_bit(new_set,i+1); /* To next set */
  528.     else
  529.       set_bit(new_set,i);
  530.   }
  531. }
  532. if (found_end)
  533. {
  534.   new_set->found_len=0; /* Set for testing if first */
  535.   bits_set=0;
  536.   for (i= (uint) ~0; (i=get_next_bit(new_set,i)) ;)
  537.   {
  538.     if ((follow[i].chr == SPACE_CHAR ||
  539.  follow[i].chr == END_OF_LINE) && ! chr)
  540.       bit_nr=i+1;
  541.     else
  542.       bit_nr=i;
  543.     if (follow[bit_nr-1].len < found_end ||
  544. (new_set->found_len &&
  545.  (chr == 0 || !follow[bit_nr].chr)))
  546.       clear_bit(new_set,i);
  547.     else
  548.     {
  549.       if (chr == 0 || !follow[bit_nr].chr)
  550.       { /* best match  */
  551. new_set->table_offset=follow[bit_nr].table_offset;
  552. if (chr || (follow[i].chr == SPACE_CHAR ||
  553.     follow[i].chr == END_OF_LINE))
  554.   new_set->found_offset=found_end; /* New match */
  555. new_set->found_len=found_end;
  556.       }
  557.       bits_set++;
  558.     }
  559.   }
  560.   if (bits_set == 1)
  561.   {
  562.     set->next[chr] = find_found(found_set,
  563. new_set->table_offset,
  564. new_set->found_offset);
  565.     free_last_set(&sets);
  566.   }
  567.   else
  568.     set->next[chr] = find_set(&sets,new_set);
  569. }
  570. else
  571.   set->next[chr] = find_set(&sets,new_set);
  572.       }
  573.     }
  574.   }
  575. /* Alloc replace structure for the replace-state-machine */
  576.   if ((replace=(REPLACE*) my_malloc(sizeof(REPLACE)*(sets.count)+
  577.     sizeof(REPLACE_STRING)*(found_sets+1)+
  578.     sizeof(my_string)*count+result_len,
  579.     MYF(MY_WME | MY_ZEROFILL))))
  580.   {
  581.     rep_str=(REPLACE_STRING*) (replace+sets.count);
  582.     to_array=(my_string*) (rep_str+found_sets+1);
  583.     to_pos=(my_string) (to_array+count);
  584.     for (i=0 ; i < count ; i++)
  585.     {
  586.       to_array[i]=to_pos;
  587.       to_pos=strmov(to_pos,to[i])+1;
  588.     }
  589.     rep_str[0].found=1;
  590.     rep_str[0].replace_string=0;
  591.     for (i=1 ; i <= found_sets ; i++)
  592.     {
  593.       pos=from[found_set[i-1].table_offset];
  594.       rep_str[i].found= !bcmp(pos,"\^",3) ? 2 : 1;
  595.       rep_str[i].replace_string=to_array[found_set[i-1].table_offset];
  596.       rep_str[i].to_offset=found_set[i-1].found_offset-start_at_word(pos);
  597.       rep_str[i].from_offset=found_set[i-1].found_offset-replace_len(pos)+
  598. end_of_word(pos);
  599.     }
  600.     for (i=0 ; i < sets.count ; i++)
  601.     {
  602.       for (j=0 ; j < 256 ; j++)
  603. if (sets.set[i].next[j] >= 0)
  604.   replace[i].next[j]=replace+sets.set[i].next[j];
  605. else
  606.   replace[i].next[j]=(REPLACE*) (rep_str+(-sets.set[i].next[j]-1));
  607.     }
  608.   }
  609.   my_free((gptr) follow,MYF(0));
  610.   free_sets(&sets);
  611.   my_free((gptr) found_set,MYF(0));
  612.   DBUG_PRINT("exit",("Replace table has %d states",sets.count));
  613.   DBUG_RETURN(replace);
  614. }
  615. static int init_sets(REP_SETS *sets,uint states)
  616. {
  617.   bzero((char*) sets,sizeof(*sets));
  618.   sets->size_of_bits=((states+7)/8);
  619.   if (!(sets->set_buffer=(REP_SET*) my_malloc(sizeof(REP_SET)*SET_MALLOC_HUNC,
  620.       MYF(MY_WME))))
  621.     return 1;
  622.   if (!(sets->bit_buffer=(uint*) my_malloc(sizeof(uint)*sets->size_of_bits*
  623.    SET_MALLOC_HUNC,MYF(MY_WME))))
  624.   {
  625.     my_free((gptr) sets->set,MYF(0));
  626.     return 1;
  627.   }
  628.   return 0;
  629. }
  630. /* Make help sets invisible for nicer codeing */
  631. static void make_sets_invisible(REP_SETS *sets)
  632. {
  633.   sets->invisible=sets->count;
  634.   sets->set+=sets->count;
  635.   sets->count=0;
  636. }
  637. static REP_SET *make_new_set(REP_SETS *sets)
  638. {
  639.   uint i,count,*bit_buffer;
  640.   REP_SET *set;
  641.   if (sets->extra)
  642.   {
  643.     sets->extra--;
  644.     set=sets->set+ sets->count++;
  645.     bzero((char*) set->bits,sizeof(uint)*sets->size_of_bits);
  646.     bzero((char*) &set->next[0],sizeof(set->next[0])*LAST_CHAR_CODE);
  647.     set->found_offset=0;
  648.     set->found_len=0;
  649.     set->table_offset= (uint) ~0;
  650.     set->size_of_bits=sets->size_of_bits;
  651.     return set;
  652.   }
  653.   count=sets->count+sets->invisible+SET_MALLOC_HUNC;
  654.   if (!(set=(REP_SET*) my_realloc((gptr) sets->set_buffer,
  655.    sizeof(REP_SET)*count,
  656.   MYF(MY_WME))))
  657.     return 0;
  658.   sets->set_buffer=set;
  659.   sets->set=set+sets->invisible;
  660.   if (!(bit_buffer=(uint*) my_realloc((gptr) sets->bit_buffer,
  661.       (sizeof(uint)*sets->size_of_bits)*count,
  662.       MYF(MY_WME))))
  663.     return 0;
  664.   sets->bit_buffer=bit_buffer;
  665.   for (i=0 ; i < count ; i++)
  666.   {
  667.     sets->set_buffer[i].bits=bit_buffer;
  668.     bit_buffer+=sets->size_of_bits;
  669.   }
  670.   sets->extra=SET_MALLOC_HUNC;
  671.   return make_new_set(sets);
  672. }
  673. static void free_last_set(REP_SETS *sets)
  674. {
  675.   sets->count--;
  676.   sets->extra++;
  677.   return;
  678. }
  679. static void free_sets(REP_SETS *sets)
  680. {
  681.   my_free((gptr)sets->set_buffer,MYF(0));
  682.   my_free((gptr)sets->bit_buffer,MYF(0));
  683.   return;
  684. }
  685. static void set_bit(REP_SET *set, uint bit)
  686. {
  687.   set->bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT);
  688.   return;
  689. }
  690. static void clear_bit(REP_SET *set, uint bit)
  691. {
  692.   set->bits[bit / WORD_BIT] &= ~ (1 << (bit % WORD_BIT));
  693.   return;
  694. }
  695. static void or_bits(REP_SET *to,REP_SET *from)
  696. {
  697.   reg1 uint i;
  698.   for (i=0 ; i < to->size_of_bits ; i++)
  699.     to->bits[i]|=from->bits[i];
  700.   return;
  701. }
  702. static void copy_bits(REP_SET *to,REP_SET *from)
  703. {
  704.   memcpy((byte*) to->bits,(byte*) from->bits,
  705.  (size_t) (sizeof(uint) * to->size_of_bits));
  706. }
  707. static int cmp_bits(REP_SET *set1,REP_SET *set2)
  708. {
  709.   return bcmp((byte*) set1->bits,(byte*) set2->bits,
  710.       sizeof(uint) * set1->size_of_bits);
  711. }
  712. /* Get next set bit from set. */
  713. static int get_next_bit(REP_SET *set,uint lastpos)
  714. {
  715.   uint pos,*start,*end,bits;
  716.   start=set->bits+ ((lastpos+1) / WORD_BIT);
  717.   end=set->bits + set->size_of_bits;
  718.   bits=start[0] & ~((1 << ((lastpos+1) % WORD_BIT)) -1);
  719.   while (! bits && ++start < end)
  720.     bits=start[0];
  721.   if (!bits)
  722.     return 0;
  723.   pos=(uint) (start-set->bits)*WORD_BIT;
  724.   while (! (bits & 1))
  725.   {
  726.     bits>>=1;
  727.     pos++;
  728.   }
  729.   return pos;
  730. }
  731. /* find if there is a same set in sets. If there is, use it and
  732.    free given set, else put in given set in sets and return it's
  733.    position */
  734. static int find_set(REP_SETS *sets,REP_SET *find)
  735. {
  736.   uint i;
  737.   for (i=0 ; i < sets->count-1 ; i++)
  738.   {
  739.     if (!cmp_bits(sets->set+i,find))
  740.     {
  741.       free_last_set(sets);
  742.       return i;
  743.     }
  744.   }
  745.   return i; /* return new postion */
  746. }
  747. /* find if there is a found_set with same table_offset & found_offset
  748.    If there is return offset to it, else add new offset and return pos.
  749.    Pos returned is -offset-2 in found_set_structure because it's is
  750.    saved in set->next and set->next[] >= 0 points to next set and
  751.    set->next[] == -1 is reserved for end without replaces.
  752.    */
  753. static int find_found(FOUND_SET *found_set,uint table_offset, int found_offset)
  754. {
  755.   int i;
  756.   for (i=0 ; (uint) i < found_sets ; i++)
  757.     if (found_set[i].table_offset == table_offset &&
  758. found_set[i].found_offset == found_offset)
  759.       return -i-2;
  760.   found_set[i].table_offset=table_offset;
  761.   found_set[i].found_offset=found_offset;
  762.   found_sets++;
  763.   return -i-2; /* return new postion */
  764. }
  765. /* Return 1 if regexp starts with b or ends with b*/
  766. static uint start_at_word(my_string pos)
  767. {
  768.   return (((!bcmp(pos,"\b",2) && pos[2]) || !bcmp(pos,"\^",2)) ? 1 : 0);
  769. }
  770. static uint end_of_word(my_string pos)
  771. {
  772.   my_string end=strend(pos);
  773.   return ((end > pos+2 && !bcmp(end-2,"\b",2)) ||
  774.   (end >= pos+2 && !bcmp(end-2,"\$",2))) ?
  775.     1 : 0;
  776. }
  777. static uint replace_len(my_string str)
  778. {
  779.   uint len=0;
  780.   while (*str)
  781.   {
  782.     if (str[0] == '\' && str[1])
  783.       str++;
  784.     str++;
  785.     len++;
  786.   }
  787.   return len;
  788. }
  789. /* The actual loop */
  790. uint replace_strings(REPLACE *rep, my_string *start,uint *max_length, my_string from)
  791. {
  792.   reg1 REPLACE *rep_pos;
  793.   reg2 REPLACE_STRING *rep_str;
  794.   my_string to,end,pos,new;
  795.   end=(to= *start) + *max_length-1;
  796.   rep_pos=rep+1;
  797.   for(;;)
  798.   {
  799.     while (!rep_pos->found)
  800.     {
  801.       rep_pos= rep_pos->next[(uchar) *from];
  802.       if (to == end)
  803.       {
  804. (*max_length)+=8192;
  805. if (!(new=my_realloc(*start,*max_length,MYF(MY_WME))))
  806.   return (uint) -1;
  807. to=new+(to - *start);
  808. end=(*start=new)+ *max_length-1;
  809.       }
  810.       *to++= *from++;
  811.     }
  812.     if (!(rep_str = ((REPLACE_STRING*) rep_pos))->replace_string)
  813.       return (uint) (to - *start)-1;
  814.     updated=1; /* Some my_string is replaced */
  815.     to-=rep_str->to_offset;
  816.     for (pos=rep_str->replace_string; *pos ; pos++)
  817.     {
  818.       if (to == end)
  819.       {
  820. (*max_length)*=2;
  821. if (!(new=my_realloc(*start,*max_length,MYF(MY_WME))))
  822.   return (uint) -1;
  823. to=new+(to - *start);
  824. end=(*start=new)+ *max_length-1;
  825.       }
  826.       *to++= *pos;
  827.     }
  828.     if (!*(from-=rep_str->from_offset) && rep_pos->found != 2)
  829.       return (uint) (to - *start);
  830.     rep_pos=rep;
  831.   }
  832. }
  833. static char *buffer; /* The buffer itself, grown as needed. */
  834. static int bufbytes; /* Number of bytes in the buffer. */
  835. static int bufread,my_eof; /* Number of bytes to get with each read(). */
  836. static uint bufalloc;
  837. static char *out_buff;
  838. static uint out_length;
  839. static int initialize_buffer()
  840. {
  841.   bufread = 8192;
  842.   bufalloc = bufread + bufread / 2;
  843.   if (!(buffer = my_malloc(bufalloc+1,MYF(MY_WME))))
  844.     return 1;
  845.   bufbytes=my_eof=0;
  846.   out_length=bufread;
  847.   if (!(out_buff=my_malloc(out_length,MYF(MY_WME))))
  848.     return(1);
  849.   return 0;
  850. }
  851. static void reset_buffer()
  852. {
  853.   bufbytes=my_eof=0;
  854. }
  855. static void free_buffer()
  856. {
  857.   my_free(buffer,MYF(MY_WME));
  858.   my_free(out_buff,MYF(MY_WME));
  859. }
  860. /* Fill the buffer retaining the last n bytes at the beginning of the
  861.    newly filled buffer (for backward context).  Returns the number of new
  862.    bytes read from disk. */
  863. static int fill_buffer_retaining(fd,n)
  864. File fd;
  865. int n;
  866. {
  867.   int i;
  868.   /* See if we need to grow the buffer. */
  869.   if ((int) bufalloc - n <= bufread)
  870.   {
  871.     while ((int) bufalloc - n <= bufread)
  872.     {
  873.       bufalloc *= 2;
  874.       bufread *= 2;
  875.     }
  876.     buffer = my_realloc(buffer, bufalloc+1, MYF(MY_WME));
  877.     if (! buffer)
  878.       return(-1);
  879.   }
  880.   /* Shift stuff down. */
  881.   bmove(buffer,buffer+bufbytes-n,(uint) n);
  882.   bufbytes = n;
  883.   if (my_eof)
  884.     return 0;
  885.   /* Read in new stuff. */
  886.   if ((i=(int) my_read(fd, buffer + bufbytes, (uint) bufread,MYF(MY_WME))) < 0)
  887.     return -1;
  888.   /* Kludge to pretend every nonempty file ends with a newline. */
  889.   if (i == 0 && bufbytes > 0 && buffer[bufbytes - 1] != 'n')
  890.   {
  891.     my_eof = i = 1;
  892.     buffer[bufbytes] = 'n';
  893.   }
  894.   bufbytes += i;
  895.   return i;
  896. }
  897. /* Return 0 if convert is ok */
  898. /* Global variable update is set if something was changed */
  899. static int convert_pipe(rep,in,out)
  900. REPLACE *rep;
  901. FILE *in,*out;
  902. {
  903.   int retain,error;
  904.   uint length;
  905.   char save_char,*end_of_line,*start_of_line;
  906.   DBUG_ENTER("convert_pipe");
  907.   updated=retain=0;
  908.   reset_buffer();
  909.   while ((error=fill_buffer_retaining(fileno(in),retain)) > 0)
  910.   {
  911.     end_of_line=buffer ;
  912.     buffer[bufbytes]=0; /* Sentinel  */
  913.     for (;;)
  914.     {
  915.       start_of_line=end_of_line;
  916.       while (end_of_line[0] != 'n' && end_of_line[0])
  917. end_of_line++;
  918.       if (end_of_line == buffer+bufbytes)
  919.       {
  920. retain= (int) (end_of_line - start_of_line);
  921. break; /* No end of line, read more */
  922.       }
  923.       save_char=end_of_line[0];
  924.       end_of_line[0]=0;
  925.       end_of_line++;
  926.       if ((length=replace_strings(rep,&out_buff,&out_length,start_of_line)) ==
  927.   (uint) -1)
  928. return 1;
  929.       if (!my_eof)
  930. out_buff[length++]=save_char; /* Don't write added newline */
  931.       if (my_fwrite(out,out_buff,length,MYF(MY_WME | MY_NABP)))
  932. DBUG_RETURN(1);
  933.     }
  934.   }
  935.   DBUG_RETURN(error);
  936. }
  937. static int convert_file(rep,name)
  938. REPLACE *rep;
  939. my_string name;
  940. {
  941.   int error;
  942.   FILE *in,*out;
  943.   char dir_buff[FN_REFLEN],*tempname;
  944.   DBUG_ENTER("convert_file");
  945.   if (!(in=my_fopen(name,O_RDONLY,MYF(MY_WME))))
  946.     DBUG_RETURN(1);
  947.   dirname_part(dir_buff,name);
  948.   tempname=my_tempnam(dir_buff,"PR",MYF(MY_WME));
  949.   if (!(out=my_fopen(tempname,(int) (O_WRONLY | O_CREAT),
  950.      MYF(MY_WME))))
  951.   {
  952.     (*free)(tempname);
  953.     my_fclose(in,MYF(0));
  954.     DBUG_RETURN(1);
  955.   }
  956.   error=convert_pipe(rep,in,out);
  957.   my_fclose(in,MYF(0)); my_fclose(out,MYF(0));
  958.   if (updated && ! error)
  959.     my_redel(name,tempname,MYF(MY_WME | MY_LINK_WARNING));
  960.   else
  961.     my_delete(tempname,MYF(MY_WME));
  962.   (*free)(tempname);
  963.   if (!silent && ! error)
  964.   {
  965.     if (updated)
  966.       printf("%s convertedn",name);
  967.     else if (verbose)
  968.       printf("%s left unchangedn",name);
  969.   }
  970.   DBUG_RETURN(error);
  971. }