~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzletest.cc

  • Committer: Monty Taylor
  • Date: 2010-06-18 00:34:51 UTC
  • mto: (1627.2.5 build)
  • mto: This revision was merged to the branch mainline in revision 1628.
  • Revision ID: mordred@inaugust.com-20100618003451-2b3fs2m2hvpch91r
Add function pointer hook for plugins to register program_options.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 
 * 
4
 
 *  Copyright (C) 2010 Vijay Samuel
 
3
 *
5
4
 *  Copyright (C) 2008 MySQL
6
5
 *
7
6
 *  This program is free software; you can redistribute it and/or modify
56
55
#include <sys/stat.h>
57
56
#include <sys/types.h>
58
57
#include <fcntl.h>
59
 
#include <boost/array.hpp>
60
 
#include <boost/foreach.hpp>
61
58
#include <boost/program_options.hpp>
62
 
#include <boost/smart_ptr.hpp>
63
59
 
64
60
#include PCRE_HEADER
65
61
 
66
62
#include <stdarg.h>
67
 
#include <boost/unordered_map.hpp>
 
63
#include <drizzled/unordered_map.h>
 
64
 
 
65
#include "errname.h"
68
66
 
69
67
/* Added this for string translation. */
70
 
#include <drizzled/gettext.h>
71
 
#include <drizzled/type/time.h>
72
 
#include <drizzled/charset.h>
73
 
#include <drizzled/typelib.h>
 
68
#include "drizzled/gettext.h"
 
69
#include "drizzled/drizzle_time.h"
 
70
#include "drizzled/charset.h"
74
71
#include <drizzled/configmake.h>
75
72
 
76
 
#define PTR_BYTE_DIFF(A,B) (ptrdiff_t) (reinterpret_cast<const unsigned char*>(A) - reinterpret_cast<const unsigned char*>(B))
77
 
 
78
73
#ifndef DRIZZLE_RETURN_SERVER_GONE
79
74
#define DRIZZLE_RETURN_HANDSHAKE_FAILED DRIZZLE_RETURN_ERROR_CODE
80
75
#endif
94
89
#define QUERY_SEND_FLAG  1
95
90
#define QUERY_REAP_FLAG  2
96
91
 
97
 
typedef boost::unordered_map<std::string, uint32_t> ErrorCodes;
98
92
ErrorCodes global_error_names;
99
93
 
100
94
enum {
109
103
static uint32_t opt_port= 0;
110
104
static uint32_t opt_max_connect_retries;
111
105
static bool silent= false, verbose= false;
 
106
static bool tty_password= false;
112
107
static bool opt_mark_progress= false;
113
108
static bool parsing_disabled= false;
114
109
static bool display_result_vertically= false,
119
114
static bool abort_on_error= true;
120
115
static bool server_initialized= false;
121
116
static bool is_windows= false;
122
 
static bool use_drizzle_protocol= false;
 
117
static bool opt_mysql= false;
 
118
const string PASSWORD_SENTINEL("\0\0\0\0\0", 5);
123
119
static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer;
124
 
static void free_all_replace();
125
120
 
126
121
std::string opt_basedir,
127
122
  opt_charsets_dir,
133
128
  password,
134
129
  opt_password,
135
130
  result_file_name,
136
 
  opt_user,
137
 
  opt_protocol;
 
131
  opt_user;
138
132
 
139
133
static uint32_t start_lineno= 0; /* Start line of current command */
140
134
 
171
165
  uint32_t lineno; /* Current line in file */
172
166
};
173
167
 
174
 
static boost::array<st_test_file, 16> file_stack;
175
 
static st_test_file* cur_file;
 
168
static struct st_test_file file_stack[16];
 
169
static struct st_test_file* cur_file;
 
170
static struct st_test_file* file_stack_end;
 
171
 
176
172
 
177
173
static const CHARSET_INFO *charset_info= &my_charset_utf8_general_ci; /* Default charset */
178
174
 
182
178
*/
183
179
static char *timer_file = NULL;
184
180
static uint64_t timer_start;
185
 
static void timer_output();
186
 
static uint64_t timer_now();
 
181
static void timer_output(void);
 
182
static uint64_t timer_now(void);
187
183
 
188
184
static uint64_t progress_start= 0;
189
185
 
204
200
 
205
201
/* if set, all results are concated and compared against this file */
206
202
 
207
 
class VAR
 
203
typedef struct st_var
208
204
{
209
 
public:
210
205
  char *name;
211
206
  int name_len;
212
207
  char *str_val;
216
211
  int int_dirty; /* do not update string if int is updated until first read */
217
212
  int alloced;
218
213
  char *env_s;
219
 
};
 
214
} VAR;
220
215
 
221
216
/*Perl/shell-like variable registers */
222
 
boost::array<VAR, 10> var_reg;
223
 
 
224
 
typedef boost::unordered_map<string, VAR *> var_hash_t;
225
 
var_hash_t var_hash;
 
217
VAR var_reg[10];
 
218
 
 
219
 
 
220
unordered_map<string, VAR *> var_hash;
226
221
 
227
222
struct st_connection
228
223
{
395
390
  struct st_match_err err[10];
396
391
  uint32_t count;
397
392
};
398
 
 
399
 
static st_expected_errors saved_expected_errors;
400
 
 
401
 
class st_command
 
393
static struct st_expected_errors saved_expected_errors;
 
394
 
 
395
struct st_command
402
396
{
403
 
public:
404
397
  char *query, *query_buf,*first_argument,*last_argument,*end;
405
398
  int first_word_len, query_len;
406
399
  bool abort_on_error;
407
400
  st_expected_errors expected_errors;
408
401
  string require_file;
409
 
  enum_commands type;
 
402
  enum enum_commands type;
410
403
 
411
404
  st_command()
412
405
    : query(NULL), query_buf(NULL), first_argument(NULL), last_argument(NULL),
418
411
 
419
412
  ~st_command()
420
413
  {
421
 
    free(query_buf);
 
414
    if (query_buf != NULL)
 
415
    {
 
416
      free(query_buf);
 
417
    }
422
418
  }
423
419
};
424
420
 
443
439
VAR* var_from_env(const char *, const char *);
444
440
VAR* var_init(VAR* v, const char *name, int name_len, const char *val,
445
441
              int val_len);
 
442
void var_free(pair<string, VAR*> v);
446
443
VAR* var_get(const char *var_name, const char** var_name_end,
447
444
             bool raw, bool ignore_not_existing);
448
445
void eval_expr(VAR* v, const char *p, const char** p_end);
449
446
bool match_delimiter(int c, const char *delim, uint32_t length);
450
447
void dump_result_to_reject_file(char *buf, int size);
451
448
void dump_result_to_log_file(const char *buf, int size);
452
 
void dump_warning_messages();
453
 
void dump_progress();
 
449
void dump_warning_messages(void);
 
450
void dump_progress(void);
454
451
 
455
452
void do_eval(string *query_eval, const char *query,
456
453
             const char *query_end, bool pass_through_escape_chars);
461
458
static char *replace_column[MAX_COLUMNS];
462
459
static uint32_t max_replace_column= 0;
463
460
void do_get_replace_column(struct st_command*);
464
 
void free_replace_column();
 
461
void free_replace_column(void);
465
462
 
466
463
/* For replace */
467
464
void do_get_replace(struct st_command *command);
468
 
void free_replace();
 
465
void free_replace(void);
469
466
 
470
467
/* For replace_regex */
471
468
void do_get_replace_regex(struct st_command *command);
 
469
void free_replace_regex(void);
 
470
 
 
471
 
 
472
void free_all_replace(void);
 
473
 
 
474
 
 
475
void free_all_replace(void){
 
476
  free_replace();
 
477
  free_replace_regex();
 
478
  free_replace_column();
 
479
}
472
480
 
473
481
void replace_append_mem(string *ds, const char *val,
474
482
                        int len);
485
493
void do_eval(string *query_eval, const char *query,
486
494
             const char *query_end, bool pass_through_escape_chars)
487
495
{
488
 
  char c, next_c;
489
 
  int escaped = 0;
 
496
  const char *p;
 
497
  register char c, next_c;
 
498
  register int escaped = 0;
490
499
  VAR *v;
491
500
 
492
 
  for (const char *p= query; (c= *p) && p < query_end; ++p)
 
501
 
 
502
  for (p= query; (c= *p) && p < query_end; ++p)
493
503
  {
494
504
    switch(c) {
495
505
    case '$':
773
783
    const struct command_arg *arg= &args[i];
774
784
    arg->ds->clear();
775
785
 
776
 
    bool known_arg_type= true;
777
786
    switch (arg->type) {
778
787
      /* A string */
779
788
    case ARG_STRING:
808
817
      break;
809
818
 
810
819
    default:
811
 
      known_arg_type= false;
 
820
      assert("Unknown argument type");
812
821
      break;
813
822
    }
814
 
    assert(known_arg_type);
815
823
 
816
824
    /* Check required arg */
817
825
    if (arg->ds->length() == 0 && arg->required)
834
842
 
835
843
static void handle_command_error(struct st_command *command, uint32_t error)
836
844
{
 
845
 
837
846
  if (error != 0)
838
847
  {
839
848
    uint32_t i;
860
869
        command->first_word_len, command->query,
861
870
        command->expected_errors.err[0].code.errnum);
862
871
  }
 
872
  return;
863
873
}
864
874
 
865
875
 
866
 
static void close_connections()
 
876
static void close_connections(void)
867
877
{
868
878
  for (--next_con; next_con >= connections; --next_con)
869
879
  {
874
884
    }
875
885
    free(next_con->name);
876
886
  }
 
887
  return;
877
888
}
878
889
 
879
890
 
880
 
static void close_files()
 
891
static void close_files(void)
881
892
{
882
 
  for (; cur_file >= file_stack.data(); cur_file--)
 
893
 
 
894
  for (; cur_file >= file_stack; cur_file--)
883
895
  {
884
896
    if (cur_file->file && cur_file->file != stdin)
 
897
    {
885
898
      fclose(cur_file->file);
886
 
    free(const_cast<char*>(cur_file->file_name));
 
899
    }
 
900
    free((unsigned char*) cur_file->file_name);
887
901
    cur_file->file_name= 0;
888
902
  }
 
903
  return;
889
904
}
890
905
 
891
 
static void free_used_memory()
 
906
 
 
907
static void free_used_memory(void)
892
908
{
 
909
  uint32_t i;
 
910
 
 
911
 
893
912
  close_connections();
894
913
  close_files();
895
 
  BOOST_FOREACH(var_hash_t::reference i, var_hash)
896
 
  {
897
 
    free(i.second->str_val);
898
 
    free(i.second->env_s);
899
 
    if (i.second->alloced)
900
 
      free(i.second);
901
 
  }
 
914
  for_each(var_hash.begin(), var_hash.end(), var_free);
902
915
  var_hash.clear();
903
 
  BOOST_FOREACH(vector<st_command*>::reference i, q_lines)
904
 
    delete i;
905
 
  for (size_t i= 0; i < var_reg.size(); i++)
 
916
 
 
917
  vector<st_command *>::iterator iter;
 
918
  for (iter= q_lines.begin() ; iter < q_lines.end() ; iter++)
 
919
  {
 
920
    struct st_command * q_line= *iter;
 
921
    delete q_line;
 
922
  }
 
923
 
 
924
  for (i= 0; i < 10; i++)
906
925
  {
907
926
    if (var_reg[i].alloced_len)
908
927
      free(var_reg[i].str_val);
909
928
  }
 
929
 
910
930
  free_all_replace();
911
931
  free(opt_pass);
 
932
 
 
933
  return;
912
934
}
913
935
 
914
936
 
933
955
      assert(0);
934
956
    }
935
957
  }
 
958
 
936
959
  exit(exit_code);
937
960
}
938
961
 
952
975
 
953
976
  /* Print the error message */
954
977
  fprintf(stderr, "drizzletest: ");
955
 
  if (cur_file && cur_file != file_stack.data())
 
978
  if (cur_file && cur_file != file_stack)
956
979
    fprintf(stderr, "In included file \"%s\": ",
957
980
            cur_file->file_name);
958
981
  if (start_lineno > 0)
1013
1036
 
1014
1037
  /* Print include filestack */
1015
1038
  fprintf(stderr, "The test '%s' is not supported by this installation\n",
1016
 
          file_stack[0].file_name);
 
1039
          file_stack->file_name);
1017
1040
  fprintf(stderr, "Detected in file %s at line %d\n",
1018
1041
          err_file->file_name, err_file->lineno);
1019
 
  while (err_file != file_stack.data())
 
1042
  while (err_file != file_stack)
1020
1043
  {
1021
1044
    err_file--;
1022
1045
    fprintf(stderr, "included from %s at line %d\n",
1047
1070
 
1048
1071
  va_start(args, fmt);
1049
1072
  fprintf(stderr, "drizzletest: ");
1050
 
  if (cur_file && cur_file != file_stack.data())
 
1073
  if (cur_file && cur_file != file_stack)
1051
1074
    fprintf(stderr, "In included file \"%s\": ",
1052
1075
            cur_file->file_name);
1053
1076
  if (start_lineno != 0)
1055
1078
  vfprintf(stderr, fmt, args);
1056
1079
  fprintf(stderr, "\n");
1057
1080
  va_end(args);
 
1081
 
 
1082
  return;
1058
1083
}
1059
1084
 
1060
1085
 
1070
1095
  if (start_lineno != 0)
1071
1096
  {
1072
1097
    ds_warning_messages.append("Warning detected ");
1073
 
    if (cur_file && cur_file != file_stack.data())
 
1098
    if (cur_file && cur_file != file_stack)
1074
1099
    {
1075
1100
      len= snprintf(buff, sizeof(buff), "in included file %s ",
1076
1101
                    cur_file->file_name);
1435
1460
  int fd;
1436
1461
  char temp_file_path[FN_REFLEN];
1437
1462
 
1438
 
  if ((fd= internal::create_temp_file(temp_file_path, TMPDIR,
 
1463
  if ((fd= internal::create_temp_file(temp_file_path, NULL,
1439
1464
                            "tmp", MYF(MY_WME))) < 0)
1440
1465
    die("Failed to create temporary file for ds");
1441
1466
 
1603
1628
VAR *var_init(VAR *v, const char *name, int name_len, const char *val,
1604
1629
              int val_len)
1605
1630
{
 
1631
  int val_alloc_len;
 
1632
  VAR *tmp_var;
1606
1633
  if (!name_len && name)
1607
1634
    name_len = strlen(name);
1608
1635
  if (!val_len && val)
1609
1636
    val_len = strlen(val) ;
1610
 
  VAR *tmp_var = v ? v : (VAR*)malloc(sizeof(*tmp_var) + name_len+1);
 
1637
  val_alloc_len = val_len + 16; /* room to grow */
 
1638
  if (!(tmp_var=v) && !(tmp_var = (VAR*)malloc(sizeof(*tmp_var)
 
1639
                                               + name_len+1)))
 
1640
    die("Out of memory");
1611
1641
 
1612
 
  tmp_var->name = name ? (char*)&tmp_var[1] : 0;
 
1642
  tmp_var->name = (name) ? (char*) tmp_var + sizeof(*tmp_var) : 0;
1613
1643
  tmp_var->alloced = (v == 0);
1614
1644
 
1615
 
  int val_alloc_len = val_len + 16; /* room to grow */
1616
 
  tmp_var->str_val = (char*)malloc(val_alloc_len+1);
 
1645
  if (!(tmp_var->str_val = (char *)malloc(val_alloc_len+1)))
 
1646
    die("Out of memory");
1617
1647
 
1618
1648
  memcpy(tmp_var->name, name, name_len);
1619
1649
  if (val)
1624
1654
  tmp_var->name_len = name_len;
1625
1655
  tmp_var->str_val_len = val_len;
1626
1656
  tmp_var->alloced_len = val_alloc_len;
1627
 
  tmp_var->int_val = val ? atoi(val) : 0;
1628
 
  tmp_var->int_dirty = false;
 
1657
  tmp_var->int_val = (val) ? atoi(val) : 0;
 
1658
  tmp_var->int_dirty = 0;
1629
1659
  tmp_var->env_s = 0;
1630
1660
  return tmp_var;
1631
1661
}
1632
1662
 
 
1663
 
 
1664
void var_free(pair<string, VAR *> v)
 
1665
{
 
1666
  free(v.second->str_val);
 
1667
  free(v.second->env_s);
 
1668
  if (v.second->alloced)
 
1669
    free(v.second);
 
1670
}
 
1671
 
 
1672
 
1633
1673
VAR* var_from_env(const char *name, const char *def_val)
1634
1674
{
1635
 
  const char *tmp= getenv(name);
1636
 
  if (!tmp)
 
1675
  const char *tmp;
 
1676
  VAR *v;
 
1677
  if (!(tmp = getenv(name)))
1637
1678
    tmp = def_val;
1638
 
  return var_hash[name] = var_init(0, name, strlen(name), tmp, strlen(tmp));
 
1679
 
 
1680
  v = var_init(0, name, strlen(name), tmp, strlen(tmp));
 
1681
  string var_name(name);
 
1682
  var_hash.insert(make_pair(var_name, v));
 
1683
  return v;
1639
1684
}
1640
1685
 
 
1686
 
1641
1687
VAR* var_get(const char *var_name, const char **var_name_end, bool raw,
1642
1688
             bool ignore_not_existing)
1643
1689
{
1644
1690
  int digit;
1645
1691
  VAR *v;
 
1692
 
1646
1693
  if (*var_name != '$')
1647
1694
    goto err;
1648
1695
  digit = *++var_name - '0';
1664
1711
      die("Too long variable name: %s", save_var_name);
1665
1712
 
1666
1713
    string save_var_name_str(save_var_name, length);
1667
 
    var_hash_t::iterator iter= var_hash.find(save_var_name_str);
 
1714
    unordered_map<string, VAR*>::iterator iter=
 
1715
      var_hash.find(save_var_name_str);
1668
1716
    if (iter == var_hash.end())
1669
1717
    {
1670
1718
      char buff[MAX_VAR_NAME_LENGTH+1];
1674
1722
    }
1675
1723
    else
1676
1724
    {
1677
 
      v= iter->second;
 
1725
      v= (*iter).second;
1678
1726
    }
1679
1727
    var_name--;  /* Point at last character */
1680
1728
  }
1681
1729
  else
1682
 
    v = &var_reg[digit];
 
1730
    v = var_reg + digit;
1683
1731
 
1684
1732
  if (!raw && v->int_dirty)
1685
1733
  {
1701
1749
static VAR *var_obtain(const char *name, int len)
1702
1750
{
1703
1751
  string var_name(name, len);
1704
 
  var_hash_t::iterator iter= var_hash.find(var_name);
 
1752
  unordered_map<string, VAR*>::iterator iter=
 
1753
    var_hash.find(var_name);
1705
1754
  if (iter != var_hash.end())
1706
 
    return iter->second;
1707
 
  return var_hash[var_name] = var_init(0, name, len, "", 0);
 
1755
    return (*iter).second;
 
1756
  VAR *v = var_init(0, name, len, "", 0);
 
1757
  var_hash.insert(make_pair(var_name, v));
 
1758
  return v;
1708
1759
}
1709
1760
 
1710
1761
 
1731
1782
    v= var_obtain(var_name, (uint32_t) (var_name_end - var_name));
1732
1783
  }
1733
1784
  else
1734
 
    v= &var_reg[digit];
 
1785
    v= var_reg + digit;
1735
1786
 
1736
1787
  eval_expr(v, var_val, (const char**) &var_val_end);
1737
1788
 
2015
2066
    eval_expr(var, value, 0);
2016
2067
  }
2017
2068
  drizzle_result_free(&res);
 
2069
 
 
2070
  return;
2018
2071
}
2019
2072
 
2020
2073
 
2045
2098
{
2046
2099
  if (*p == '$')
2047
2100
  {
2048
 
    VAR *vp= var_get(p, p_end, 0, 0);
2049
 
    if (vp)
 
2101
    VAR *vp;
 
2102
    if ((vp= var_get(p, p_end, 0, 0)))
2050
2103
      var_copy(v, vp);
2051
2104
    return;
2052
2105
  }
2107
2160
  }
2108
2161
  internal::fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
2109
2162
 
 
2163
  if (cur_file == file_stack_end)
 
2164
    die("Source directives are nesting too deep");
2110
2165
  cur_file++;
2111
 
  if (cur_file == &*file_stack.end())
2112
 
    die("Source directives are nesting too deep");
2113
2166
  if (!(cur_file->file= fopen(buff, "r")))
2114
2167
  {
2115
2168
    cur_file--;
2171
2224
}
2172
2225
 
2173
2226
 
2174
 
static void init_builtin_echo()
 
2227
static void init_builtin_echo(void)
2175
2228
{
2176
2229
  builtin_echo[0]= 0;
 
2230
  return;
2177
2231
}
2178
2232
 
2179
2233
 
2425
2479
 
2426
2480
  error= internal::my_delete(ds_filename.c_str(), MYF(0)) != 0;
2427
2481
  handle_command_error(command, error);
 
2482
  return;
2428
2483
}
2429
2484
 
2430
2485
 
2459
2514
  error= (internal::my_copy(ds_from_file.c_str(), ds_to_file.c_str(),
2460
2515
                  MYF(MY_DONT_OVERWRITE_FILE)) != 0);
2461
2516
  handle_command_error(command, error);
 
2517
  return;
2462
2518
}
2463
2519
 
2464
2520
 
2496
2552
    die("You must write a 4 digit octal number for mode");
2497
2553
 
2498
2554
  handle_command_error(command, chmod(ds_file.c_str(), mode));
 
2555
  return;
2499
2556
}
2500
2557
 
2501
2558
 
2525
2582
 
2526
2583
  error= (access(ds_filename.c_str(), F_OK) != 0);
2527
2584
  handle_command_error(command, error);
 
2585
  return;
2528
2586
}
2529
2587
 
2530
2588
 
2553
2611
 
2554
2612
  error= mkdir(ds_dirname.c_str(), (0777 & internal::my_umask_dir)) != 0;
2555
2613
  handle_command_error(command, error);
 
2614
  return;
2556
2615
}
2557
2616
 
2558
2617
/*
2580
2639
 
2581
2640
  error= rmdir(ds_dirname.c_str()) != 0;
2582
2641
  handle_command_error(command, error);
 
2642
  return;
2583
2643
}
2584
2644
 
2585
2645
 
2818
2878
  }
2819
2879
 
2820
2880
  handle_command_error(command, error);
 
2881
  return;
2821
2882
}
2822
2883
 
2823
2884
 
2867
2928
 
2868
2929
  if (drizzle_quit(&con->con,&result, &ret))
2869
2930
    drizzle_result_free(&result);
 
2931
 
 
2932
  return;
2870
2933
}
2871
2934
 
2872
2935
 
2963
3026
  internal::my_delete(temp_file_path, MYF(0));
2964
3027
 
2965
3028
  handle_command_error(command, WEXITSTATUS(error));
 
3029
  return;
2966
3030
}
2967
3031
 
2968
3032
 
3136
3200
  when ndb binlog is on, this call will wait until last updated epoch
3137
3201
  (locally in the drizzled) has been received into the binlog
3138
3202
*/
3139
 
static int do_save_master_pos()
 
3203
static int do_save_master_pos(void)
3140
3204
{
3141
3205
  drizzle_result_st res;
3142
3206
  drizzle_return_t ret;
3252
3316
  bool error= false;
3253
3317
  char *p= command->first_argument;
3254
3318
  char *sleep_start, *sleep_end= command->end;
3255
 
  double sleep_val= 0;
 
3319
  double sleep_val;
3256
3320
 
3257
3321
  while (my_isspace(charset_info, *p))
3258
3322
    p++;
3275
3339
    sleep_val= opt_sleep;
3276
3340
 
3277
3341
  if (sleep_val)
3278
 
    usleep(sleep_val * 1000000);
 
3342
    usleep((uint32_t) (sleep_val * 1000000L));
3279
3343
  command->last_argument= sleep_end;
3280
3344
  return 0;
3281
3345
}
3282
3346
 
3283
3347
 
3284
 
static void do_get_file_name(st_command *command, string &dest)
 
3348
static void do_get_file_name(struct st_command *command, string &dest)
3285
3349
{
3286
 
  char *p= command->first_argument;
 
3350
  char *p= command->first_argument, *name;
3287
3351
  if (!*p)
3288
3352
    die("Missing file name argument");
3289
 
  char *name= p;
 
3353
  name= p;
3290
3354
  while (*p && !my_isspace(charset_info,*p))
3291
3355
    p++;
3292
3356
  if (*p)
3321
3385
    abort_not_supported_test("Test requires charset '%s'", charset_name);
3322
3386
}
3323
3387
 
3324
 
static void fill_global_error_names()
3325
 
{
3326
 
  drizzle_result_st res;
3327
 
  drizzle_return_t ret;
3328
 
  drizzle_row_t row;
3329
 
  drizzle_con_st *con= &cur_con->con;
3330
 
 
3331
 
  global_error_names.clear();
3332
 
 
3333
 
  const std::string ds_query("select error_name, error_code "
3334
 
                             "from data_dictionary.errors");
3335
 
  if (drizzle_query_str(con, &res, ds_query.c_str(), &ret) == NULL ||
3336
 
      ret != DRIZZLE_RETURN_OK)
3337
 
  {
3338
 
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
3339
 
    {
3340
 
      die("Error running query '%s': %d %s", ds_query.c_str(),
3341
 
          drizzle_result_error_code(&res), drizzle_result_error(&res));
3342
 
      drizzle_result_free(&res);
3343
 
    }
3344
 
    else
3345
 
    {
3346
 
      die("Error running query '%s': %d %s", ds_query.c_str(), ret,
3347
 
          drizzle_con_error(con));
3348
 
    }
3349
 
  }
3350
 
  if (drizzle_result_column_count(&res) == 0 ||
3351
 
      drizzle_result_buffer(&res) != DRIZZLE_RETURN_OK)
3352
 
  {
3353
 
    drizzle_result_free(&res);
3354
 
    die("Query '%s' didn't return a result set", ds_query.c_str());
3355
 
  }
3356
 
 
3357
 
  while ((row= drizzle_row_next(&res)) && row[0])
3358
 
  {
3359
 
    /*
3360
 
      Concatenate all fields in the first row with tab in between
3361
 
      and assign that string to the $variable
3362
 
    */
3363
 
    size_t *lengths= drizzle_row_field_sizes(&res);
3364
 
    try
3365
 
    {
3366
 
      global_error_names[string(row[0], lengths[0])] = boost::lexical_cast<uint32_t>(string(row[1], lengths[1]));
3367
 
    }
3368
 
    catch (boost::bad_lexical_cast &ex)
3369
 
    {
3370
 
      drizzle_result_free(&res);
3371
 
      die("Invalid error_code from Drizzle: %s", ex.what());
3372
 
    }
3373
 
 
3374
 
  }
3375
 
 
3376
 
  drizzle_result_free(&res);
3377
 
}
3378
 
 
3379
3388
static uint32_t get_errcode_from_name(char *error_name, char *error_end)
3380
3389
{
3381
3390
  size_t err_name_len= error_end - error_name;
3382
3391
  string error_name_s(error_name, err_name_len);
3383
3392
 
3384
 
  ErrorCodes::iterator it= global_error_names.find(error_name_s);
3385
 
  if (it != global_error_names.end())
3386
 
    return it->second;
3387
 
 
3388
 
  die("Unknown SQL error name '%s'", error_name_s.c_str());
3389
 
  return 0;
 
3393
  uint32_t code= global_error_names.getErrorCode(error_name_s);
 
3394
 
 
3395
  if (!code)
 
3396
    die("Unknown SQL error name '%s'", error_name_s.c_str());
 
3397
 
 
3398
  return(code);
3390
3399
}
3391
3400
 
3392
3401
static void do_get_errcodes(struct st_command *command)
3454
3463
    {
3455
3464
      die("The error name definition must start with an uppercase E");
3456
3465
    }
3457
 
    else if (*p == 'H')
 
3466
    else
3458
3467
    {
3459
 
      /* Error name string */
3460
 
 
3461
 
      to->code.errnum= get_errcode_from_name(p, end);
 
3468
      long val;
 
3469
      char *start= p;
 
3470
      /* Check that the string passed to str2int only contain digits */
 
3471
      while (*p && p != end)
 
3472
      {
 
3473
        if (!my_isdigit(charset_info, *p))
 
3474
          die("Invalid argument to error: '%s' - "              \
 
3475
              "the errno may only consist of digits[0-9]",
 
3476
              command->first_argument);
 
3477
        p++;
 
3478
      }
 
3479
 
 
3480
      /* Convert the sting to int */
 
3481
      istringstream buff(start);
 
3482
      if ((buff >> val).fail())
 
3483
        die("Invalid argument to error: '%s'", command->first_argument);
 
3484
 
 
3485
      to->code.errnum= (uint32_t) val;
3462
3486
      to->type= ERR_ERRNO;
3463
3487
    }
3464
 
    else
3465
 
    {
3466
 
      die ("You must either use the SQLSTATE or built in drizzle error label, numbers are not accepted");
3467
 
    }
3468
3488
    to++;
3469
3489
    count++;
3470
3490
 
3826
3846
{
3827
3847
  uint32_t con_port= opt_port;
3828
3848
  const char *con_options;
3829
 
  bool con_ssl= 0;
 
3849
  bool con_ssl= 0, con_compress= 0;
3830
3850
  struct st_connection* con_slot;
3831
3851
 
3832
3852
  string ds_connection_name;
3892
3912
      end++;
3893
3913
    if (!strncmp(con_options, "SSL", 3))
3894
3914
      con_ssl= 1;
 
3915
    else if (!strncmp(con_options, "COMPRESS", 8))
 
3916
      con_compress= 1;
3895
3917
    else
3896
3918
      die("Illegal option to connect: %.*s",
3897
3919
          (int) (end - con_options), con_options);
3917
3939
    die("Failed on drizzle_create()");
3918
3940
  if (!drizzle_con_create(con_slot->drizzle, &con_slot->con))
3919
3941
    die("Failed on drizzle_con_create()");
3920
 
  drizzle_con_add_options(&con_slot->con, use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
 
3942
  if (opt_mysql)
 
3943
    drizzle_con_add_options(&con_slot->con, DRIZZLE_CON_MYSQL);
3921
3944
 
3922
3945
  /* Use default db name */
3923
3946
  if (ds_database.length() == 0)
4004
4027
{
4005
4028
  char *p= command->first_argument;
4006
4029
  const char *expr_start, *expr_end;
 
4030
  VAR v;
4007
4031
  const char *cmd_name= (cmd == cmd_while ? "while" : "if");
4008
4032
  bool not_expr= false;
4009
4033
 
4046
4070
  if (*p && *p != '{')
4047
4071
    die("Missing '{' after %s. Found \"%s\"", cmd_name, p);
4048
4072
 
4049
 
  VAR v;
4050
4073
  var_init(&v,0,0,0,0);
4051
4074
  eval_expr(&v, expr_start, &expr_end);
4052
4075
 
4182
4205
      }
4183
4206
      free((unsigned char*) cur_file->file_name);
4184
4207
      cur_file->file_name= 0;
4185
 
      if (cur_file == file_stack.data())
 
4208
      if (cur_file == file_stack)
4186
4209
      {
4187
4210
        /* We're back at the first file, check if
4188
4211
           all { have matching }
4416
4439
        end++;
4417
4440
      save= *end;
4418
4441
      *end= 0;
4419
 
      type= command_typelib.find_type(start, 1+2);
 
4442
      type= find_type(start, &command_typelib, 1+2);
4420
4443
      if (type)
4421
4444
        warning_msg("Embedded drizzletest command '--%s' detected in "
4422
4445
                    "query '%s' was this intentional? ",
4622
4645
          log_file);
4623
4646
}
4624
4647
 
4625
 
void dump_progress()
 
4648
void dump_progress(void)
4626
4649
{
4627
4650
  char progress_file[FN_REFLEN];
4628
4651
  str_to_file(internal::fn_format(progress_file, result_file_name.c_str(),
4632
4655
              ds_progress.c_str(), ds_progress.length());
4633
4656
}
4634
4657
 
4635
 
void dump_warning_messages()
 
4658
void dump_warning_messages(void)
4636
4659
{
4637
4660
  char warn_file[FN_REFLEN];
4638
4661
 
4697
4720
    for (i = 0; i < num_fields; i++)
4698
4721
    {
4699
4722
      column= drizzle_column_next(res);
4700
 
      if (row[i] && (drizzle_column_type(column) == DRIZZLE_COLUMN_TYPE_TINY))
4701
 
      {
4702
 
        if (boost::lexical_cast<uint32_t>(row[i]))
4703
 
        {
4704
 
          if ((drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_UNSIGNED))
4705
 
          {
4706
 
            append_field(ds, i, column, "YES", 3, false);
4707
 
          }
4708
 
          else
4709
 
          {
4710
 
            append_field(ds, i, column, "TRUE", 4, false);
4711
 
          }
4712
 
        }
4713
 
        else
4714
 
        {
4715
 
          if ((drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_UNSIGNED))
4716
 
          {
4717
 
            append_field(ds, i, column, "NO", 2, false);
4718
 
          }
4719
 
          else
4720
 
          {
4721
 
            append_field(ds, i, column, "FALSE", 5, false);
4722
 
          }
4723
 
        }
4724
 
      }
4725
 
      else
4726
 
      {
4727
 
        append_field(ds, i, column,
4728
 
                     (const char*)row[i], lengths[i], !row[i]);
4729
 
      }
 
4723
      append_field(ds, i, column,
 
4724
                   (const char*)row[i], lengths[i], !row[i]);
4730
4725
    }
4731
4726
    if (!display_result_vertically)
4732
4727
      ds->append("\n");
4770
4765
    ds->append("\t", 1);
4771
4766
    replace_append_uint(ds, drizzle_column_size(column));
4772
4767
    ds->append("\t", 1);
4773
 
    if (drizzle_column_type(column) == DRIZZLE_COLUMN_TYPE_TINY)
4774
 
    {
4775
 
      replace_append_uint(ds, 1);
4776
 
    }
4777
 
    else
4778
 
    {
4779
 
      replace_append_uint(ds, drizzle_column_max_size(column));
4780
 
    }
 
4768
    replace_append_uint(ds, drizzle_column_max_size(column));
4781
4769
    ds->append("\t", 1);
4782
4770
    ds->append((char*) ((drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_NOT_NULL) ? "N" : "Y"), 1);
4783
4771
    ds->append("\t", 1);
5274
5262
 
5275
5263
  save= command->query[command->first_word_len];
5276
5264
  command->query[command->first_word_len]= 0;
5277
 
  type= command_typelib.find_type(command->query, 1+2);
 
5265
  type= find_type(command->query, &command_typelib, 1+2);
5278
5266
  command->query[command->first_word_len]= save;
5279
5267
  if (type > 0)
5280
5268
  {
5318
5306
        */
5319
5307
        save= command->query[command->first_word_len-1];
5320
5308
        command->query[command->first_word_len-1]= 0;
5321
 
        if (command_typelib.find_type(command->query, 1+2) > 0)
 
5309
        if (find_type(command->query, &command_typelib, 1+2) > 0)
5322
5310
          die("Extra delimiter \";\" found");
5323
5311
        command->query[command->first_word_len-1]= save;
5324
5312
 
5374
5362
{
5375
5363
  if (in_opt_max_connect_retries > 10000 || opt_max_connect_retries<1)
5376
5364
  {
5377
 
    cout << N_("Error: Invalid Value for opt_max_connect_retries"); 
 
5365
    cout<<N_("Error: Invalid Value for opt_max_connect_retries"); 
5378
5366
    exit(-1);
5379
5367
  }
5380
5368
  opt_max_connect_retries= in_opt_max_connect_retries;
5384
5372
{
5385
5373
  if (in_opt_tail_lines > 10000)
5386
5374
  {
5387
 
    cout << N_("Error: Invalid Value for opt_tail_lines"); 
 
5375
    cout<<N_("Error: Invalid Value for opt_tail_lines"); 
5388
5376
    exit(-1);
5389
5377
  }
5390
5378
  opt_tail_lines= in_opt_tail_lines;
5394
5382
{
5395
5383
  if (in_opt_sleep < -1)
5396
5384
  {
5397
 
    cout << N_("Error: Invalid Value for opt_sleep"); 
 
5385
    cout<<N_("Error: Invalid Value for opt_sleep"); 
5398
5386
    exit(-1);
5399
5387
  }
5400
5388
  opt_sleep= in_opt_sleep;
5401
5389
}
5402
5390
 
 
5391
static pair<string, string> parse_password_arg(std::string s)
 
5392
{
 
5393
  if (s.find("--password") == 0)
 
5394
  {
 
5395
    if (s == "--password")
 
5396
    {
 
5397
      tty_password= true;
 
5398
      //check if no argument is passed.
 
5399
      return make_pair("password", PASSWORD_SENTINEL);
 
5400
    }
 
5401
 
 
5402
    if (s.substr(10,3) == "=\"\"" || s.substr(10,3) == "=''")
 
5403
    {
 
5404
      // Check if --password="" or --password=''
 
5405
      return make_pair("password", PASSWORD_SENTINEL);
 
5406
    }
 
5407
    
 
5408
    if(s.substr(10) == "=" && s.length() == 11)
 
5409
    {
 
5410
      // check if --password= and return a default value
 
5411
      return make_pair("password", PASSWORD_SENTINEL);
 
5412
    }
 
5413
 
 
5414
    if(s.length()>12 && (s[10] == '"' || s[10] == '\''))
 
5415
    {
 
5416
      // check if --password has quotes, remove quotes and return the value
 
5417
      return make_pair("password", s.substr(11,s.length()-1));
 
5418
    }
 
5419
 
 
5420
    // if all above are false, it implies that --password=value, return value.
 
5421
    return make_pair("password", s.substr(11));
 
5422
  }
 
5423
 
 
5424
  else
 
5425
  {
 
5426
    return make_pair(string(""), string(""));
 
5427
  } 
 
5428
}
 
5429
 
5403
5430
int main(int argc, char **argv)
5404
5431
{
5405
5432
try
5412
5439
 
5413
5440
  TMPDIR[0]= 0;
5414
5441
 
5415
 
  internal::my_init();
5416
 
 
5417
5442
  po::options_description commandline_options("Options used only in command line");
5418
5443
  commandline_options.add_options()
5419
5444
  ("help,?", "Display this help and exit.")
5450
5475
  "Directory for log files")
5451
5476
  ("max-connect-retries", po::value<uint32_t>(&opt_max_connect_retries)->default_value(500)->notifier(&check_retries),
5452
5477
  "Max number of connection attempts when connecting to server")
5453
 
  ("quiet,s", po::value<bool>(&silent)->default_value(false)->zero_tokens(),
 
5478
  ("quiet,s", po::value<bool>(&silent)->default_value(0)->zero_tokens(),
5454
5479
  "Suppress all normal output.")
5455
5480
  ("record,r", "Record output of test_file into result file.")
5456
5481
  ("result-file,R", po::value<string>(&result_file_name)->default_value(""),
5466
5491
 
5467
5492
  ("host,h", po::value<string>(&opt_host)->default_value("localhost"),
5468
5493
  "Connect to host.")
 
5494
  ("mysql,m", po::value<bool>(&opt_mysql)->default_value(true)->zero_tokens(),
 
5495
  N_("Use MySQL Protocol."))
5469
5496
  ("password,P", po::value<string>(&password)->default_value("PASSWORD_SENTINEL"),
5470
5497
  "Password to use when connecting to server.")
5471
5498
  ("port,p", po::value<uint32_t>(&opt_port)->default_value(0),
5472
5499
  "Port number to use for connection or 0 for default")
5473
 
  ("protocol", po::value<string>(&opt_protocol),
5474
 
  "The protocol of connection (mysql or drizzle).")
 
5500
  ("protocol", po::value<string>(),
 
5501
  "The protocol of connection (tcp,socket,pipe,memory).")
5475
5502
  ("user,u", po::value<string>(&opt_user)->default_value(""),
5476
5503
  "User for login.")
5477
5504
  ;
5488
5515
  std::string system_config_dir_client(SYSCONFDIR); 
5489
5516
  system_config_dir_client.append("/drizzle/client.cnf");
5490
5517
 
5491
 
  std::string user_config_dir((getenv("XDG_CONFIG_HOME")? getenv("XDG_CONFIG_HOME"):"~/.config"));
5492
 
 
5493
 
  if (user_config_dir.compare(0, 2, "~/") == 0)
5494
 
  {
5495
 
    const char *homedir= getenv("HOME");
5496
 
    if (homedir != NULL)
5497
 
      user_config_dir.replace(0, 1, homedir);
5498
 
  }
5499
 
 
5500
5518
  po::variables_map vm;
5501
5519
 
5502
 
  // Disable allow_guessing
5503
 
  int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
5504
 
 
5505
5520
  po::store(po::command_line_parser(argc, argv).options(long_options).
5506
 
            style(style).positional(p).extra_parser(parse_password_arg).run(),
5507
 
            vm);
 
5521
            positional(p).extra_parser(parse_password_arg).run(), vm);
5508
5522
 
5509
5523
  if (! vm["no-defaults"].as<bool>())
5510
5524
  {
5511
 
    std::string user_config_dir_test(user_config_dir);
5512
 
    user_config_dir_test.append("/drizzle/drizzletest.cnf"); 
5513
 
 
5514
 
    std::string user_config_dir_client(user_config_dir);
5515
 
    user_config_dir_client.append("/drizzle/client.cnf");
5516
 
 
5517
 
    ifstream user_test_ifs(user_config_dir_test.c_str());
 
5525
    ifstream user_test_ifs("~/.drizzle/drizzletest.cnf");
5518
5526
    po::store(parse_config_file(user_test_ifs, test_options), vm);
5519
 
 
5520
 
    ifstream user_client_ifs(user_config_dir_client.c_str());
5521
 
    po::store(parse_config_file(user_client_ifs, client_options), vm);
5522
 
 
 
5527
 
5523
5528
    ifstream system_test_ifs(system_config_dir_test.c_str());
5524
5529
    store(parse_config_file(system_test_ifs, test_options), vm);
5525
5530
 
 
5531
    ifstream user_client_ifs("~/.drizzle/client.cnf");
 
5532
    po::store(parse_config_file(user_client_ifs, client_options), vm);
 
5533
 
5526
5534
    ifstream system_client_ifs(system_config_dir_client.c_str());
5527
5535
    po::store(parse_config_file(system_client_ifs, client_options), vm);
5528
5536
  }
5539
5547
  next_con= connections + 1;
5540
5548
 
5541
5549
  /* Init file stack */
5542
 
  memset(file_stack.data(), 0, sizeof(file_stack));
5543
 
  cur_file= file_stack.data();
 
5550
  memset(file_stack, 0, sizeof(file_stack));
 
5551
  file_stack_end=
 
5552
    file_stack + (sizeof(file_stack)/sizeof(struct st_test_file)) - 1;
 
5553
  cur_file= file_stack;
5544
5554
 
5545
5555
  /* Init block stack */
5546
5556
  memset(block_stack, 0, sizeof(block_stack));
5579
5589
      tmp= buff;
5580
5590
    }
5581
5591
    internal::fn_format(buff, tmp.c_str(), "", "", MY_UNPACK_FILENAME);
5582
 
    assert(cur_file == file_stack.data() && cur_file->file == 0);
 
5592
    assert(cur_file == file_stack && cur_file->file == 0);
5583
5593
    if (!(cur_file->file= fopen(buff, "r")))
5584
5594
    {
5585
5595
      fprintf(stderr, _("Could not open '%s' for reading: errno = %d"), buff, errno);
5607
5617
    unlink(timer_file);       /* Ignore error, may not exist */
5608
5618
  }
5609
5619
 
5610
 
  if (vm.count("protocol"))
5611
 
  {
5612
 
    std::transform(opt_protocol.begin(), opt_protocol.end(),
5613
 
      opt_protocol.begin(), ::tolower);
5614
 
 
5615
 
    if (not opt_protocol.compare("mysql"))
5616
 
      use_drizzle_protocol=false;
5617
 
    else if (not opt_protocol.compare("drizzle"))
5618
 
      use_drizzle_protocol=true;
5619
 
    else
5620
 
    {
5621
 
      cout << _("Error: Unknown protocol") << " '" << opt_protocol << "'" << endl;
5622
 
      exit(-1);
5623
 
    }
5624
 
  }
5625
 
 
5626
5620
  if (vm.count("port"))
5627
5621
  {
5628
5622
    /* If the port number is > 65535 it is not a valid port
5635
5629
    }
5636
5630
  }
5637
5631
 
5638
 
  if( vm.count("password") )
 
5632
  if (vm.count("password"))
5639
5633
  {
5640
5634
    if (!opt_password.empty())
5641
5635
      opt_password.erase();
5648
5642
      opt_password= password;
5649
5643
      tty_password= false;
5650
5644
    }
 
5645
    char *start= (char *)password.c_str();
 
5646
    char *temp_pass= (char *)password.c_str();
 
5647
    while (*temp_pass)
 
5648
    {
 
5649
        /* Overwriting password with 'x' */
 
5650
        *temp_pass++= 'x';
 
5651
    }
 
5652
    if (*start)
 
5653
    {
 
5654
      start[1]= 0;
 
5655
    }
5651
5656
  }
5652
5657
  else
5653
5658
  {
5684
5689
  }
5685
5690
 
5686
5691
  server_initialized= 1;
5687
 
  if (cur_file == file_stack.data() && cur_file->file == 0)
 
5692
  if (cur_file == file_stack && cur_file->file == 0)
5688
5693
  {
5689
5694
    cur_file->file= stdin;
5690
5695
    cur_file->file_name= strdup("<stdin>");
5697
5702
    die("Failed in drizzle_create()");
5698
5703
  if (!( drizzle_con_create(cur_con->drizzle, &cur_con->con)))
5699
5704
    die("Failed in drizzle_con_create()");
5700
 
  drizzle_con_add_options(&cur_con->con, use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
 
5705
  if (opt_mysql)
 
5706
    drizzle_con_add_options(&cur_con->con, DRIZZLE_CON_MYSQL);
5701
5707
 
5702
5708
  if (!(cur_con->name = strdup("default")))
5703
5709
    die("Out of memory");
5704
5710
  safe_connect(&cur_con->con, cur_con->name, opt_host, opt_user, opt_pass,
5705
5711
               opt_db, opt_port);
5706
5712
 
5707
 
  fill_global_error_names();
5708
 
 
5709
5713
  /* Use all time until exit if no explicit 'start_timer' */
5710
5714
  timer_start= timer_now();
5711
5715
 
6109
6113
  the time between executing the two commands.
6110
6114
*/
6111
6115
 
6112
 
void timer_output()
 
6116
void timer_output(void)
6113
6117
{
6114
6118
  if (timer_file)
6115
6119
  {
6123
6127
}
6124
6128
 
6125
6129
 
6126
 
uint64_t timer_now()
 
6130
uint64_t timer_now(void)
6127
6131
{
6128
6132
#if defined(HAVE_GETHRTIME)
6129
6133
  return gethrtime()/1000/1000;
6163
6167
  start= buff= (char *)malloc(strlen(from)+1);
6164
6168
  while (*from)
6165
6169
  {
 
6170
    char *to;
6166
6171
    uint32_t column_number;
6167
6172
 
6168
 
    char *to= get_string(&buff, &from, command);
 
6173
    to= get_string(&buff, &from, command);
6169
6174
    if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS)
6170
6175
      die("Wrong column number to replace_column in '%s'", command->query);
6171
6176
    if (!*from)
6184
6189
 
6185
6190
void free_replace_column()
6186
6191
{
6187
 
  for (uint32_t i= 0 ; i < max_replace_column; i++)
 
6192
  uint32_t i;
 
6193
  for (i=0 ; i < max_replace_column ; i++)
6188
6194
  {
6189
 
    free(replace_column[i]);
6190
 
    replace_column[i]= 0;
 
6195
    if (replace_column[i])
 
6196
    {
 
6197
      free(replace_column[i]);
 
6198
      replace_column[i]= 0;
 
6199
    }
6191
6200
  }
6192
6201
  max_replace_column= 0;
6193
6202
}
6208
6217
} POINTER_ARRAY;
6209
6218
 
6210
6219
struct st_replace;
6211
 
struct st_replace *init_replace(const char **from, const char **to, uint32_t count,
6212
 
                                char *word_end_chars);
 
6220
struct st_replace *init_replace(char * *from, char * *to, uint32_t count,
 
6221
                                char * word_end_chars);
6213
6222
int insert_pointer_name(POINTER_ARRAY *pa,char * name);
6214
6223
void replace_strings_append(struct st_replace *rep, string* ds,
6215
6224
                            const char *from, int len);
 
6225
void free_pointer_array(POINTER_ARRAY *pa);
6216
6226
 
6217
 
st_replace *glob_replace= NULL;
6218
 
// boost::scoped_ptr<st_replace> glob_replace;
 
6227
struct st_replace *glob_replace= NULL;
6219
6228
 
6220
6229
/*
6221
6230
  Get arguments for replace. The syntax is:
6225
6234
  variable is replaced.
6226
6235
*/
6227
6236
 
6228
 
static void free_pointer_array(POINTER_ARRAY *pa)
6229
 
{
6230
 
  if (!pa->typelib.count)
6231
 
    return;
6232
 
  pa->typelib.count=0;
6233
 
  free((char*) pa->typelib.type_names);
6234
 
  pa->typelib.type_names=0;
6235
 
  free(pa->str);
6236
 
}
6237
 
 
6238
6237
void do_get_replace(struct st_command *command)
6239
6238
{
6240
6239
  uint32_t i;
6266
6265
    if (my_isspace(charset_info,i))
6267
6266
      *pos++= i;
6268
6267
  *pos=0;          /* End pointer */
6269
 
  if (!(glob_replace= init_replace(from_array.typelib.type_names,
6270
 
                                   to_array.typelib.type_names,
6271
 
                                   from_array.typelib.count,
 
6268
  if (!(glob_replace= init_replace((char**) from_array.typelib.type_names,
 
6269
                                   (char**) to_array.typelib.type_names,
 
6270
                                   (uint32_t) from_array.typelib.count,
6272
6271
                                   word_end_chars)))
6273
6272
    die("Can't initialize replace from '%s'", command->query);
6274
6273
  free_pointer_array(&from_array);
6281
6280
 
6282
6281
void free_replace()
6283
6282
{
6284
 
  free(glob_replace);
6285
 
  glob_replace=0;
 
6283
 
 
6284
  if (glob_replace)
 
6285
  {
 
6286
    free(glob_replace);
 
6287
    glob_replace=0;
 
6288
  }
 
6289
  return;
6286
6290
}
6287
6291
 
6288
6292
 
6302
6306
void replace_strings_append(REPLACE *rep, string* ds,
6303
6307
                            const char *str, int len)
6304
6308
{
6305
 
  REPLACE *rep_pos;
6306
 
  REPLACE_STRING *rep_str;
 
6309
  register REPLACE *rep_pos;
 
6310
  register REPLACE_STRING *rep_str;
6307
6311
  const char *start, *from;
6308
6312
 
6309
6313
 
6356
6360
                 i.e. repeat the matching until the end of the string */
6357
6361
};
6358
6362
 
6359
 
class st_replace_regex
 
6363
struct st_replace_regex
6360
6364
{
6361
 
public:
6362
 
  st_replace_regex(char* expr);
6363
 
  int multi_reg_replace(char* val);
 
6365
  DYNAMIC_ARRAY regex_arr; /* stores a list of st_regex subsitutions */
6364
6366
 
6365
6367
  /*
6366
6368
    Temporary storage areas for substitutions. To reduce unnessary copying
6369
6371
    st_regex substition. At the end of substitutions  buf points to the
6370
6372
    one containing the final result.
6371
6373
  */
6372
 
  typedef vector<st_regex> regex_arr_t;
6373
 
 
6374
 
  char* buf_;
 
6374
  char* buf;
6375
6375
  char* even_buf;
6376
6376
  char* odd_buf;
6377
6377
  int even_buf_len;
6378
6378
  int odd_buf_len;
6379
 
  boost::array<char, 8 << 10> buf0_;
6380
 
  boost::array<char, 8 << 10> buf1_;
6381
 
  regex_arr_t regex_arr;
6382
6379
};
6383
6380
 
6384
 
boost::scoped_ptr<st_replace_regex> glob_replace_regex;
 
6381
struct st_replace_regex *glob_replace_regex= 0;
6385
6382
 
6386
6383
int reg_replace(char** buf_p, int* buf_len_p, char *pattern, char *replace,
6387
6384
                char *string, int icase, int global);
6423
6420
  Returns: st_replace_regex struct with pairs of substitutions
6424
6421
*/
6425
6422
 
6426
 
st_replace_regex::st_replace_regex(char* expr)
 
6423
static struct st_replace_regex* init_replace_regex(char* expr)
6427
6424
{
 
6425
  struct st_replace_regex* res;
 
6426
  char* buf,*expr_end;
 
6427
  char* p;
 
6428
  char* buf_p;
6428
6429
  uint32_t expr_len= strlen(expr);
6429
6430
  char last_c = 0;
6430
 
  st_regex reg;
6431
 
 
6432
 
  char* buf= new char[expr_len];
6433
 
  char* expr_end= expr + expr_len;
6434
 
  char* p= expr;
6435
 
  char* buf_p= buf;
 
6431
  struct st_regex reg;
 
6432
 
 
6433
  res=(st_replace_regex*)malloc(sizeof(*res)+expr_len);
 
6434
  if (!res)
 
6435
    return NULL;
 
6436
  my_init_dynamic_array(&res->regex_arr,sizeof(struct st_regex),128,128);
 
6437
 
 
6438
  buf= (char*)res + sizeof(*res);
 
6439
  expr_end= expr + expr_len;
 
6440
  p= expr;
 
6441
  buf_p= buf;
6436
6442
 
6437
6443
  /* for each regexp substitution statement */
6438
6444
  while (p < expr_end)
6448
6454
 
6449
6455
    if (p == expr_end || ++p == expr_end)
6450
6456
    {
6451
 
      if (!regex_arr.empty())
 
6457
      if (res->regex_arr.elements)
6452
6458
        break;
6453
6459
      else
6454
6460
        goto err;
6487
6493
      p++;
6488
6494
      reg.global= 1;
6489
6495
    }
6490
 
    regex_arr.push_back(reg);
 
6496
 
 
6497
    /* done parsing the statement, now place it in regex_arr */
 
6498
    if (insert_dynamic(&res->regex_arr,(unsigned char*) &reg))
 
6499
      die("Out of memory");
6491
6500
  }
6492
 
  odd_buf_len= even_buf_len= buf0_.size();
6493
 
  even_buf= buf0_.data();
6494
 
  odd_buf= buf1_.data();
6495
 
  buf_= even_buf;
 
6501
  res->odd_buf_len= res->even_buf_len= 8192;
 
6502
  res->even_buf= (char*)malloc(res->even_buf_len);
 
6503
  res->odd_buf= (char*)malloc(res->odd_buf_len);
 
6504
  res->buf= res->even_buf;
6496
6505
 
6497
 
  return;
 
6506
  return res;
6498
6507
 
6499
6508
err:
 
6509
  free(res);
6500
6510
  die("Error parsing replace_regex \"%s\"", expr);
 
6511
  return 0;
6501
6512
}
6502
6513
 
6503
6514
/*
6519
6530
  in one pass
6520
6531
*/
6521
6532
 
6522
 
int st_replace_regex::multi_reg_replace(char* val)
 
6533
static int multi_reg_replace(struct st_replace_regex* r,char* val)
6523
6534
{
6524
 
  char* in_buf= val;
6525
 
  char* out_buf= even_buf;
6526
 
  int* buf_len_p= &even_buf_len;
6527
 
  buf_= 0;
 
6535
  uint32_t i;
 
6536
  char* in_buf, *out_buf;
 
6537
  int* buf_len_p;
 
6538
 
 
6539
  in_buf= val;
 
6540
  out_buf= r->even_buf;
 
6541
  buf_len_p= &r->even_buf_len;
 
6542
  r->buf= 0;
6528
6543
 
6529
6544
  /* For each substitution, do the replace */
6530
 
  BOOST_FOREACH(regex_arr_t::const_reference i, regex_arr)
 
6545
  for (i= 0; i < r->regex_arr.elements; i++)
6531
6546
  {
 
6547
    struct st_regex re;
6532
6548
    char* save_out_buf= out_buf;
6533
 
    if (!reg_replace(&out_buf, buf_len_p, i.pattern, i.replace,
6534
 
                     in_buf, i.icase, i.global))
 
6549
 
 
6550
    get_dynamic(&r->regex_arr,(unsigned char*)&re,i);
 
6551
 
 
6552
    if (!reg_replace(&out_buf, buf_len_p, re.pattern, re.replace,
 
6553
                     in_buf, re.icase, re.global))
6535
6554
    {
6536
6555
      /* if the buffer has been reallocated, make adjustements */
6537
6556
      if (save_out_buf != out_buf)
6538
6557
      {
6539
 
        if (save_out_buf == even_buf)
6540
 
          even_buf= out_buf;
 
6558
        if (save_out_buf == r->even_buf)
 
6559
          r->even_buf= out_buf;
6541
6560
        else
6542
 
          odd_buf= out_buf;
 
6561
          r->odd_buf= out_buf;
6543
6562
      }
6544
 
      buf_= out_buf;
 
6563
 
 
6564
      r->buf= out_buf;
6545
6565
      if (in_buf == val)
6546
 
        in_buf= odd_buf;
6547
 
      std::swap(in_buf, out_buf);
6548
 
      buf_len_p= (out_buf == even_buf) ? &even_buf_len : &odd_buf_len;
 
6566
        in_buf= r->odd_buf;
 
6567
 
 
6568
      std::swap(in_buf,out_buf);
 
6569
 
 
6570
      buf_len_p= (out_buf == r->even_buf) ? &r->even_buf_len :
 
6571
        &r->odd_buf_len;
6549
6572
    }
6550
6573
  }
6551
 
  return buf_ == 0;
 
6574
 
 
6575
  return (r->buf == 0);
6552
6576
}
6553
6577
 
6554
6578
/*
6563
6587
void do_get_replace_regex(struct st_command *command)
6564
6588
{
6565
6589
  char *expr= command->first_argument;
6566
 
  glob_replace_regex.reset(new st_replace_regex(expr));
 
6590
  free_replace_regex();
 
6591
  if (!(glob_replace_regex=init_replace_regex(expr)))
 
6592
    die("Could not init replace_regex");
6567
6593
  command->last_argument= command->end;
6568
6594
}
6569
6595
 
 
6596
void free_replace_regex()
 
6597
{
 
6598
  if (glob_replace_regex)
 
6599
  {
 
6600
    delete_dynamic(&glob_replace_regex->regex_arr);
 
6601
    free(glob_replace_regex->even_buf);
 
6602
    free(glob_replace_regex->odd_buf);
 
6603
    free(glob_replace_regex);
 
6604
    glob_replace_regex=0;
 
6605
  }
 
6606
}
 
6607
 
 
6608
 
 
6609
 
6570
6610
/*
6571
6611
  Performs a regex substitution
6572
6612
 
6630
6670
    /* Repeatedly replace the string with the matched regex */
6631
6671
    string subject(in_string);
6632
6672
    size_t replace_length= strlen(replace);
6633
 
    size_t length_of_replacement= strlen(replace);
6634
6673
    size_t current_position= 0;
6635
6674
    int rc= 0;
6636
 
 
6637
 
    while (true) 
 
6675
    while(0 >= (rc= pcre_exec(re, NULL, subject.c_str() + current_position, subject.length() - current_position,
 
6676
                      0, 0, ovector, 3)))
6638
6677
    {
6639
 
      rc= pcre_exec(re, NULL, subject.c_str(), subject.length(), 
6640
 
                    current_position, 0, ovector, 3);
6641
 
      if (rc < 0)
6642
 
      {
6643
 
        break;
6644
 
      }
6645
 
 
6646
6678
      current_position= static_cast<size_t>(ovector[0]);
6647
6679
      replace_length= static_cast<size_t>(ovector[1] - ovector[0]);
6648
 
      subject.replace(current_position, replace_length, replace, length_of_replacement);
6649
 
      current_position= current_position + length_of_replacement;
 
6680
      subject.replace(current_position, replace_length, replace, replace_length);
6650
6681
    }
6651
6682
 
6652
6683
    char *new_buf = (char *) malloc(subject.length() + 1);
6673
6704
#define SET_MALLOC_HUNC 64
6674
6705
#define LAST_CHAR_CODE 259
6675
6706
 
6676
 
class REP_SET
6677
 
{
6678
 
public:
6679
 
  void internal_set_bit(uint32_t bit);
6680
 
  void internal_clear_bit(uint32_t bit);
6681
 
  void or_bits(const REP_SET *from);
6682
 
  void copy_bits(const REP_SET *from);
6683
 
  int cmp_bits(const REP_SET *set2) const;
6684
 
  int get_next_bit(uint32_t lastpos) const;
6685
 
 
 
6707
typedef struct st_rep_set {
6686
6708
  uint32_t  *bits;        /* Pointer to used sets */
6687
6709
  short next[LAST_CHAR_CODE];    /* Pointer to next sets */
6688
6710
  uint32_t  found_len;      /* Best match to date */
6689
6711
  int  found_offset;
6690
6712
  uint32_t  table_offset;
6691
6713
  uint32_t  size_of_bits;      /* For convinience */
6692
 
};
6693
 
 
6694
 
class REP_SETS
6695
 
{
6696
 
public:
6697
 
  int find_set(const REP_SET *find);
6698
 
  void free_last_set();
6699
 
  void free_sets();
6700
 
  void make_sets_invisible();
6701
 
 
 
6714
} REP_SET;
 
6715
 
 
6716
typedef struct st_rep_sets {
6702
6717
  uint32_t    count;      /* Number of sets */
6703
6718
  uint32_t    extra;      /* Extra sets in buffer */
6704
 
  uint32_t    invisible;    /* Sets not shown */
 
6719
  uint32_t    invisible;    /* Sets not chown */
6705
6720
  uint32_t    size_of_bits;
6706
6721
  REP_SET  *set,*set_buffer;
6707
6722
  uint32_t    *bit_buffer;
6708
 
};
 
6723
} REP_SETS;
6709
6724
 
6710
 
struct FOUND_SET 
6711
 
{
 
6725
typedef struct st_found_set {
6712
6726
  uint32_t table_offset;
6713
6727
  int found_offset;
6714
 
};
 
6728
} FOUND_SET;
6715
6729
 
6716
 
struct FOLLOWS
6717
 
{
 
6730
typedef struct st_follow {
6718
6731
  int chr;
6719
6732
  uint32_t table_offset;
6720
6733
  uint32_t len;
6721
 
};
6722
 
 
6723
 
int init_sets(REP_SETS *sets, uint32_t states);
 
6734
} FOLLOWS;
 
6735
 
 
6736
 
 
6737
int init_sets(REP_SETS *sets,uint32_t states);
6724
6738
REP_SET *make_new_set(REP_SETS *sets);
6725
 
int find_found(FOUND_SET *found_set, uint32_t table_offset, int found_offset);
6726
 
 
6727
 
static uint32_t found_sets= 0;
6728
 
 
6729
 
static uint32_t replace_len(const char *str)
 
6739
void make_sets_invisible(REP_SETS *sets);
 
6740
void free_last_set(REP_SETS *sets);
 
6741
void free_sets(REP_SETS *sets);
 
6742
void internal_set_bit(REP_SET *set, uint32_t bit);
 
6743
void internal_clear_bit(REP_SET *set, uint32_t bit);
 
6744
void or_bits(REP_SET *to,REP_SET *from);
 
6745
void copy_bits(REP_SET *to,REP_SET *from);
 
6746
int cmp_bits(REP_SET *set1,REP_SET *set2);
 
6747
int get_next_bit(REP_SET *set,uint32_t lastpos);
 
6748
int find_set(REP_SETS *sets,REP_SET *find);
 
6749
int find_found(FOUND_SET *found_set,uint32_t table_offset,
 
6750
               int found_offset);
 
6751
uint32_t start_at_word(char * pos);
 
6752
uint32_t end_of_word(char * pos);
 
6753
 
 
6754
static uint32_t found_sets=0;
 
6755
 
 
6756
 
 
6757
static uint32_t replace_len(char * str)
6730
6758
{
6731
6759
  uint32_t len=0;
6732
6760
  while (*str)
6739
6767
  return len;
6740
6768
}
6741
6769
 
6742
 
/* Return 1 if regexp starts with \b or ends with \b*/
6743
 
 
6744
 
static bool start_at_word(const char *pos)
6745
 
{
6746
 
  return ((!memcmp(pos, "\\b",2) && pos[2]) || !memcmp(pos, "\\^", 2));
6747
 
}
6748
 
 
6749
 
static bool end_of_word(const char *pos)
6750
 
{
6751
 
  const char *end= strchr(pos, '\0');
6752
 
  return (end > pos+2 && !memcmp(end-2, "\\b", 2)) || (end >= pos+2 && !memcmp(end-2, "\\$",2));
6753
 
}
6754
 
 
6755
6770
/* Init a replace structure for further calls */
6756
6771
 
6757
 
REPLACE *init_replace(const char **from, const char **to, uint32_t count, char *word_end_chars)
 
6772
REPLACE *init_replace(char * *from, char * *to,uint32_t count,
 
6773
                      char * word_end_chars)
6758
6774
{
6759
 
  const int SPACE_CHAR= 256;
6760
 
  const int START_OF_LINE= 257;
6761
 
  const int END_OF_LINE= 258;
 
6775
  static const int SPACE_CHAR= 256;
 
6776
  static const int START_OF_LINE= 257;
 
6777
  static const int END_OF_LINE= 258;
6762
6778
 
6763
6779
  uint32_t i,j,states,set_nr,len,result_len,max_length,found_end,bits_set,bit_nr;
6764
6780
  int used_sets,chr,default_state;
6765
6781
  char used_chars[LAST_CHAR_CODE],is_word_end[256];
6766
 
  char *to_pos, **to_array;
 
6782
  char * pos, *to_pos, **to_array;
 
6783
  REP_SETS sets;
 
6784
  REP_SET *set,*start_states,*word_states,*new_set;
 
6785
  FOLLOWS *follow,*follow_ptr;
 
6786
  REPLACE *replace;
 
6787
  FOUND_SET *found_set;
 
6788
  REPLACE_STRING *rep_str;
 
6789
 
6767
6790
 
6768
6791
  /* Count number of states */
6769
6792
  for (i=result_len=max_length=0 , states=2 ; i < count ; i++)
6783
6806
  for (i=0 ; word_end_chars[i] ; i++)
6784
6807
    is_word_end[(unsigned char) word_end_chars[i]]=1;
6785
6808
 
6786
 
  REP_SETS sets;
6787
 
  REP_SET *set,*start_states,*word_states,*new_set;
6788
 
  REPLACE_STRING *rep_str;
6789
 
  if (init_sets(&sets, states))
6790
 
    return 0;
 
6809
  if (init_sets(&sets,states))
 
6810
    return(0);
6791
6811
  found_sets=0;
6792
 
  vector<FOUND_SET> found_set(max_length * count);
 
6812
  if (!(found_set= (FOUND_SET*) malloc(sizeof(FOUND_SET)*max_length*count)))
 
6813
                                
 
6814
  {
 
6815
    free_sets(&sets);
 
6816
    return(0);
 
6817
  }
6793
6818
  make_new_set(&sets);      /* Set starting set */
6794
 
  sets.make_sets_invisible();      /* Hide previus sets */
 
6819
  make_sets_invisible(&sets);      /* Hide previus sets */
6795
6820
  used_sets=-1;
6796
6821
  word_states=make_new_set(&sets);    /* Start of new word */
6797
6822
  start_states=make_new_set(&sets);    /* This is first state */
6798
 
  vector<FOLLOWS> follow(states + 2);
6799
 
  FOLLOWS *follow_ptr= &follow[1];
 
6823
  if (!(follow=(FOLLOWS*) malloc((states+2)*sizeof(FOLLOWS))))
 
6824
  {
 
6825
    free_sets(&sets);
 
6826
    free(found_set);
 
6827
    return(0);
 
6828
  }
 
6829
 
6800
6830
  /* Init follow_ptr[] */
6801
 
  for (i=0, states=1; i < count; i++)
 
6831
  for (i=0, states=1, follow_ptr=follow+1 ; i < count ; i++)
6802
6832
  {
6803
6833
    if (from[i][0] == '\\' && from[i][1] == '^')
6804
6834
    {
6805
 
      start_states->internal_set_bit(states + 1);
 
6835
      internal_set_bit(start_states,states+1);
6806
6836
      if (!from[i][2])
6807
6837
      {
6808
6838
        start_states->table_offset=i;
6811
6841
    }
6812
6842
    else if (from[i][0] == '\\' && from[i][1] == '$')
6813
6843
    {
6814
 
      start_states->internal_set_bit(states);
6815
 
      word_states->internal_set_bit(states);
 
6844
      internal_set_bit(start_states,states);
 
6845
      internal_set_bit(word_states,states);
6816
6846
      if (!from[i][2] && start_states->table_offset == UINT32_MAX)
6817
6847
      {
6818
6848
        start_states->table_offset=i;
6821
6851
    }
6822
6852
    else
6823
6853
    {
6824
 
      word_states->internal_set_bit(states);
 
6854
      internal_set_bit(word_states,states);
6825
6855
      if (from[i][0] == '\\' && (from[i][1] == 'b' && from[i][2]))
6826
 
        start_states->internal_set_bit(states + 1);
 
6856
        internal_set_bit(start_states,states+1);
6827
6857
      else
6828
 
        start_states->internal_set_bit(states);
 
6858
        internal_set_bit(start_states,states);
6829
6859
    }
6830
 
    const char *pos;
6831
 
    for (pos= from[i], len=0; *pos ; pos++)
 
6860
    for (pos=from[i], len=0; *pos ; pos++)
6832
6861
    {
6833
6862
      if (*pos == '\\' && *(pos+1))
6834
6863
      {
6871
6900
  }
6872
6901
 
6873
6902
 
6874
 
  for (set_nr=0; set_nr < sets.count ; set_nr++)
 
6903
  for (set_nr=0,pos=0 ; set_nr < sets.count ; set_nr++)
6875
6904
  {
6876
6905
    set=sets.set+set_nr;
6877
6906
    default_state= 0;        /* Start from beginning */
6878
6907
 
6879
6908
    /* If end of found-string not found or start-set with current set */
6880
6909
 
6881
 
    for (i= UINT32_MAX; (i= set->get_next_bit(i)) ;)
 
6910
    for (i= UINT32_MAX; (i=get_next_bit(set,i)) ;)
6882
6911
    {
6883
 
      if (!follow[i].chr && !default_state)
6884
 
        default_state= find_found(&found_set.front(), set->table_offset, set->found_offset+1);
 
6912
      if (!follow[i].chr)
 
6913
      {
 
6914
        if (! default_state)
 
6915
          default_state= find_found(found_set,set->table_offset,
 
6916
                                    set->found_offset+1);
 
6917
      }
6885
6918
    }
6886
 
    sets.set[used_sets].copy_bits(set);    /* Save set for changes */
 
6919
    copy_bits(sets.set+used_sets,set);    /* Save set for changes */
6887
6920
    if (!default_state)
6888
 
      sets.set[used_sets].or_bits(sets.set);  /* Can restart from start */
 
6921
      or_bits(sets.set+used_sets,sets.set);  /* Can restart from start */
6889
6922
 
6890
6923
    /* Find all chars that follows current sets */
6891
6924
    memset(used_chars, 0, sizeof(used_chars));
6892
 
    for (i= UINT32_MAX; (i= sets.set[used_sets].get_next_bit(i)) ;)
 
6925
    for (i= UINT32_MAX; (i=get_next_bit(sets.set+used_sets,i)) ;)
6893
6926
    {
6894
6927
      used_chars[follow[i].chr]=1;
6895
6928
      if ((follow[i].chr == SPACE_CHAR && !follow[i+1].chr &&
6899
6932
 
6900
6933
    /* Mark word_chars used if \b is in state */
6901
6934
    if (used_chars[SPACE_CHAR])
6902
 
      for (const char *pos= word_end_chars ; *pos ; pos++)
 
6935
      for (pos= word_end_chars ; *pos ; pos++)
6903
6936
        used_chars[(int) (unsigned char) *pos] = 1;
6904
6937
 
6905
6938
    /* Handle other used characters */
6916
6949
        new_set->found_offset=set->found_offset+1;
6917
6950
        found_end=0;
6918
6951
 
6919
 
        for (i= UINT32_MAX ; (i= sets.set[used_sets].get_next_bit(i)) ; )
 
6952
        for (i= UINT32_MAX ; (i=get_next_bit(sets.set+used_sets,i)) ; )
6920
6953
        {
6921
6954
          if (!follow[i].chr || follow[i].chr == chr ||
6922
6955
              (follow[i].chr == SPACE_CHAR &&
6928
6961
                follow[i].len > found_end)
6929
6962
              found_end=follow[i].len;
6930
6963
            if (chr && follow[i].chr)
6931
 
              new_set->internal_set_bit(i + 1);    /* To next set */
 
6964
              internal_set_bit(new_set,i+1);    /* To next set */
6932
6965
            else
6933
 
              new_set->internal_set_bit(i);
 
6966
              internal_set_bit(new_set,i);
6934
6967
          }
6935
6968
        }
6936
6969
        if (found_end)
6937
6970
        {
6938
6971
          new_set->found_len=0;      /* Set for testing if first */
6939
6972
          bits_set=0;
6940
 
          for (i= UINT32_MAX; (i= new_set->get_next_bit(i)) ;)
 
6973
          for (i= UINT32_MAX; (i=get_next_bit(new_set,i)) ;)
6941
6974
          {
6942
6975
            if ((follow[i].chr == SPACE_CHAR ||
6943
6976
                 follow[i].chr == END_OF_LINE) && ! chr)
6947
6980
            if (follow[bit_nr-1].len < found_end ||
6948
6981
                (new_set->found_len &&
6949
6982
                 (chr == 0 || !follow[bit_nr].chr)))
6950
 
              new_set->internal_clear_bit(i);
 
6983
              internal_clear_bit(new_set,i);
6951
6984
            else
6952
6985
            {
6953
6986
              if (chr == 0 || !follow[bit_nr].chr)
6963
6996
          }
6964
6997
          if (bits_set == 1)
6965
6998
          {
6966
 
            set->next[chr] = find_found(&found_set.front(), new_set->table_offset, new_set->found_offset);
6967
 
            sets.free_last_set();
 
6999
            set->next[chr] = find_found(found_set,
 
7000
                                        new_set->table_offset,
 
7001
                                        new_set->found_offset);
 
7002
            free_last_set(&sets);
6968
7003
          }
6969
7004
          else
6970
 
            set->next[chr] = sets.find_set(new_set);
 
7005
            set->next[chr] = find_set(&sets,new_set);
6971
7006
        }
6972
7007
        else
6973
 
          set->next[chr] = sets.find_set(new_set);
 
7008
          set->next[chr] = find_set(&sets,new_set);
6974
7009
      }
6975
7010
    }
6976
7011
  }
6977
7012
 
6978
7013
  /* Alloc replace structure for the replace-state-machine */
6979
7014
 
6980
 
  REPLACE *replace= (REPLACE*)malloc(sizeof(REPLACE) * (sets.count)
6981
 
    + sizeof(REPLACE_STRING) * (found_sets + 1) + sizeof(char*) * count + result_len);
6982
 
  if (replace)
 
7015
  if ((replace=(REPLACE*) malloc(sizeof(REPLACE)*(sets.count)+
 
7016
                                 sizeof(REPLACE_STRING)*(found_sets+1)+
 
7017
                                 sizeof(char *)*count+result_len)))
6983
7018
  {
6984
7019
    memset(replace, 0, sizeof(REPLACE)*(sets.count)+
6985
7020
                       sizeof(REPLACE_STRING)*(found_sets+1)+
6996
7031
    rep_str[0].replace_string=0;
6997
7032
    for (i=1 ; i <= found_sets ; i++)
6998
7033
    {
6999
 
      const char *pos= from[found_set[i-1].table_offset];
 
7034
      pos=from[found_set[i-1].table_offset];
7000
7035
      rep_str[i].found= !memcmp(pos, "\\^", 3) ? 2 : 1;
7001
 
      rep_str[i].replace_string= to_array[found_set[i-1].table_offset];
7002
 
      rep_str[i].to_offset= found_set[i-1].found_offset-start_at_word(pos);
7003
 
      rep_str[i].from_offset= found_set[i-1].found_offset-replace_len(pos) + end_of_word(pos);
 
7036
      rep_str[i].replace_string=to_array[found_set[i-1].table_offset];
 
7037
      rep_str[i].to_offset=found_set[i-1].found_offset-start_at_word(pos);
 
7038
      rep_str[i].from_offset=found_set[i-1].found_offset-replace_len(pos)+
 
7039
        end_of_word(pos);
7004
7040
    }
7005
7041
    for (i=0 ; i < sets.count ; i++)
7006
7042
    {
7011
7047
          replace[i].next[j]=(REPLACE*) (rep_str+(-sets.set[i].next[j]-1));
7012
7048
    }
7013
7049
  }
7014
 
  sets.free_sets();
7015
 
  return replace;
 
7050
  free(follow);
 
7051
  free_sets(&sets);
 
7052
  free(found_set);
 
7053
  return(replace);
7016
7054
}
7017
7055
 
7018
7056
 
7033
7071
 
7034
7072
/* Make help sets invisible for nicer codeing */
7035
7073
 
7036
 
void REP_SETS::make_sets_invisible()
 
7074
void make_sets_invisible(REP_SETS *sets)
7037
7075
{
7038
 
  invisible= count;
7039
 
  set += count;
7040
 
  count= 0;
 
7076
  sets->invisible=sets->count;
 
7077
  sets->set+=sets->count;
 
7078
  sets->count=0;
7041
7079
}
7042
7080
 
7043
7081
REP_SET *make_new_set(REP_SETS *sets)
7075
7113
  return make_new_set(sets);
7076
7114
}
7077
7115
 
7078
 
void REP_SETS::free_last_set()
7079
 
{
7080
 
  count--;
7081
 
  extra++;
7082
 
}
7083
 
 
7084
 
void REP_SETS::free_sets()
7085
 
{
7086
 
  free(set_buffer);
7087
 
  free(bit_buffer);
7088
 
}
7089
 
 
7090
 
void REP_SET::internal_set_bit(uint32_t bit)
7091
 
{
7092
 
  bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT);
7093
 
}
7094
 
 
7095
 
void REP_SET::internal_clear_bit(uint32_t bit)
7096
 
{
7097
 
  bits[bit / WORD_BIT] &= ~ (1 << (bit % WORD_BIT));
7098
 
}
7099
 
 
7100
 
 
7101
 
void REP_SET::or_bits(const REP_SET *from)
7102
 
{
7103
 
  for (uint32_t i= 0 ; i < size_of_bits; i++)
7104
 
    bits[i]|=from->bits[i];
7105
 
}
7106
 
 
7107
 
void REP_SET::copy_bits(const REP_SET *from)
7108
 
{
7109
 
  memcpy(bits, from->bits, sizeof(uint32_t) * size_of_bits);
7110
 
}
7111
 
 
7112
 
int REP_SET::cmp_bits(const REP_SET *set2) const
7113
 
{
7114
 
  return memcmp(bits, set2->bits, sizeof(uint32_t) * size_of_bits);
7115
 
}
 
7116
void free_last_set(REP_SETS *sets)
 
7117
{
 
7118
  sets->count--;
 
7119
  sets->extra++;
 
7120
  return;
 
7121
}
 
7122
 
 
7123
void free_sets(REP_SETS *sets)
 
7124
{
 
7125
  free(sets->set_buffer);
 
7126
  free(sets->bit_buffer);
 
7127
  return;
 
7128
}
 
7129
 
 
7130
void internal_set_bit(REP_SET *set, uint32_t bit)
 
7131
{
 
7132
  set->bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT);
 
7133
  return;
 
7134
}
 
7135
 
 
7136
void internal_clear_bit(REP_SET *set, uint32_t bit)
 
7137
{
 
7138
  set->bits[bit / WORD_BIT] &= ~ (1 << (bit % WORD_BIT));
 
7139
  return;
 
7140
}
 
7141
 
 
7142
 
 
7143
void or_bits(REP_SET *to,REP_SET *from)
 
7144
{
 
7145
  register uint32_t i;
 
7146
  for (i=0 ; i < to->size_of_bits ; i++)
 
7147
    to->bits[i]|=from->bits[i];
 
7148
  return;
 
7149
}
 
7150
 
 
7151
void copy_bits(REP_SET *to,REP_SET *from)
 
7152
{
 
7153
  memcpy(to->bits,from->bits,
 
7154
         (size_t) (sizeof(uint32_t) * to->size_of_bits));
 
7155
}
 
7156
 
 
7157
int cmp_bits(REP_SET *set1,REP_SET *set2)
 
7158
{
 
7159
  return memcmp(set1->bits,set2->bits, sizeof(uint32_t) * set1->size_of_bits);
 
7160
}
 
7161
 
7116
7162
 
7117
7163
/* Get next set bit from set. */
7118
7164
 
7119
 
int REP_SET::get_next_bit(uint32_t lastpos) const
 
7165
int get_next_bit(REP_SET *set,uint32_t lastpos)
7120
7166
{
7121
 
  uint32_t *start= bits + ((lastpos+1) / WORD_BIT);
7122
 
  uint32_t *end= bits + size_of_bits;
7123
 
  uint32_t bits0= start[0] & ~((1 << ((lastpos+1) % WORD_BIT)) -1);
7124
 
 
7125
 
  while (!bits0 && ++start < end)
7126
 
    bits0= start[0];
7127
 
  if (!bits0)
 
7167
  uint32_t pos,*start,*end,bits;
 
7168
 
 
7169
  start=set->bits+ ((lastpos+1) / WORD_BIT);
 
7170
  end=set->bits + set->size_of_bits;
 
7171
  bits=start[0] & ~((1 << ((lastpos+1) % WORD_BIT)) -1);
 
7172
 
 
7173
  while (! bits && ++start < end)
 
7174
    bits=start[0];
 
7175
  if (!bits)
7128
7176
    return 0;
7129
 
  uint32_t pos= (start - bits) * WORD_BIT;
7130
 
  while (!(bits0 & 1))
 
7177
  pos=(uint32_t) (start-set->bits)*WORD_BIT;
 
7178
  while (! (bits & 1))
7131
7179
  {
7132
 
    bits0 >>=1;
 
7180
    bits>>=1;
7133
7181
    pos++;
7134
7182
  }
7135
7183
  return pos;
7139
7187
   free given set, else put in given set in sets and return its
7140
7188
   position */
7141
7189
 
7142
 
int REP_SETS::find_set(const REP_SET *find)
 
7190
int find_set(REP_SETS *sets,REP_SET *find)
7143
7191
{
7144
 
  uint32_t i= 0;
7145
 
  for (; i < count - 1; i++)
 
7192
  uint32_t i;
 
7193
  for (i=0 ; i < sets->count-1 ; i++)
7146
7194
  {
7147
 
    if (!set[i].cmp_bits(find))
 
7195
    if (!cmp_bits(sets->set+i,find))
7148
7196
    {
7149
 
      free_last_set();
 
7197
      free_last_set(sets);
7150
7198
      return i;
7151
7199
    }
7152
7200
  }
7160
7208
   set->next[] == -1 is reserved for end without replaces.
7161
7209
*/
7162
7210
 
7163
 
int find_found(FOUND_SET *found_set, uint32_t table_offset, int found_offset)
 
7211
int find_found(FOUND_SET *found_set,uint32_t table_offset, int found_offset)
7164
7212
{
7165
 
  uint32_t i= 0;
7166
 
  for (; i < found_sets; i++)
7167
 
  {
 
7213
  int i;
 
7214
  for (i=0 ; (uint32_t) i < found_sets ; i++)
7168
7215
    if (found_set[i].table_offset == table_offset &&
7169
7216
        found_set[i].found_offset == found_offset)
7170
 
      return - i - 2;
7171
 
  }
7172
 
  found_set[i].table_offset= table_offset;
7173
 
  found_set[i].found_offset= found_offset;
 
7217
      return -i-2;
 
7218
  found_set[i].table_offset=table_offset;
 
7219
  found_set[i].found_offset=found_offset;
7174
7220
  found_sets++;
7175
 
  return - i - 2; // return new postion
 
7221
  return -i-2;        /* return new postion */
 
7222
}
 
7223
 
 
7224
/* Return 1 if regexp starts with \b or ends with \b*/
 
7225
 
 
7226
uint32_t start_at_word(char * pos)
 
7227
{
 
7228
  return (((!memcmp(pos, "\\b",2) && pos[2]) ||
 
7229
           !memcmp(pos, "\\^", 2)) ? 1 : 0);
 
7230
}
 
7231
 
 
7232
uint32_t end_of_word(char * pos)
 
7233
{
 
7234
  char * end= strchr(pos, '\0');
 
7235
  return ((end > pos+2 && !memcmp(end-2, "\\b", 2)) ||
 
7236
          (end >= pos+2 && !memcmp(end-2, "\\$",2))) ? 1 : 0;
7176
7237
}
7177
7238
 
7178
7239
/****************************************************************************
7251
7312
} /* insert_pointer_name */
7252
7313
 
7253
7314
 
 
7315
/* free pointer array */
 
7316
 
 
7317
void free_pointer_array(POINTER_ARRAY *pa)
 
7318
{
 
7319
  if (pa->typelib.count)
 
7320
  {
 
7321
    pa->typelib.count=0;
 
7322
    free((char*) pa->typelib.type_names);
 
7323
    pa->typelib.type_names=0;
 
7324
    free(pa->str);
 
7325
  }
 
7326
} /* free_pointer_array */
 
7327
 
 
7328
 
7254
7329
/* Functions that uses replace and replace_regex */
7255
7330
 
7256
7331
/* Append the string to ds, with optional replace */
7257
 
void replace_append_mem(string *ds, const char *val, int len)
 
7332
void replace_append_mem(string *ds,
 
7333
                        const char *val, int len)
7258
7334
{
7259
7335
  char *v= strdup(val);
7260
7336
 
7261
 
  if (glob_replace_regex && !glob_replace_regex->multi_reg_replace(v))
 
7337
  if (glob_replace_regex)
7262
7338
  {
7263
 
    v= glob_replace_regex->buf_;
7264
 
    len= strlen(v);
 
7339
    /* Regex replace */
 
7340
    if (!multi_reg_replace(glob_replace_regex, v))
 
7341
    {
 
7342
      v= glob_replace_regex->buf;
 
7343
      len= strlen(v);
 
7344
    }
7265
7345
  }
 
7346
 
7266
7347
  if (glob_replace)
7267
7348
  {
7268
7349
    /* Normal replace */
7269
7350
    replace_strings_append(glob_replace, ds, v, len);
7270
7351
  }
7271
7352
  else
 
7353
  {
7272
7354
    ds->append(v, len);
 
7355
  }
7273
7356
}
7274
7357
 
7275
7358
 
7338
7421
 
7339
7422
  return;
7340
7423
}
7341
 
 
7342
 
static void free_all_replace()
7343
 
{
7344
 
  free_replace();
7345
 
  glob_replace_regex.reset();
7346
 
  free_replace_column();
7347
 
}