56
55
#include <sys/stat.h>
57
56
#include <sys/types.h>
59
#include <boost/array.hpp>
60
#include <boost/foreach.hpp>
61
58
#include <boost/program_options.hpp>
62
#include <boost/smart_ptr.hpp>
64
60
#include PCRE_HEADER
66
62
#include <stdarg.h>
67
#include <boost/unordered_map.hpp>
63
#include <drizzled/unordered_map.h>
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>
76
#define PTR_BYTE_DIFF(A,B) (ptrdiff_t) (reinterpret_cast<const unsigned char*>(A) - reinterpret_cast<const unsigned char*>(B))
78
73
#ifndef DRIZZLE_RETURN_SERVER_GONE
79
74
#define DRIZZLE_RETURN_HANDSHAKE_FAILED DRIZZLE_RETURN_ERROR_CODE
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();
126
121
std::string opt_basedir,
127
122
opt_charsets_dir,
171
165
uint32_t lineno; /* Current line in file */
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;
177
173
static const CHARSET_INFO *charset_info= &my_charset_utf8_general_ci; /* Default charset */
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);
188
184
static uint64_t progress_start= 0;
395
390
struct st_match_err err[10];
399
static st_expected_errors saved_expected_errors;
393
static struct st_expected_errors saved_expected_errors;
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;
402
enum enum_commands type;
412
405
: query(NULL), query_buf(NULL), first_argument(NULL), last_argument(NULL),
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,
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);
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);
466
463
/* For replace */
467
464
void do_get_replace(struct st_command *command);
465
void free_replace(void);
470
467
/* For replace_regex */
471
468
void do_get_replace_regex(struct st_command *command);
469
void free_replace_regex(void);
472
void free_all_replace(void);
475
void free_all_replace(void){
477
free_replace_regex();
478
free_replace_column();
473
481
void replace_append_mem(string *ds, const char *val,
875
885
free(next_con->name);
880
static void close_files()
891
static void close_files(void)
882
for (; cur_file >= file_stack.data(); cur_file--)
894
for (; cur_file >= file_stack; cur_file--)
884
896
if (cur_file->file && cur_file->file != stdin)
885
898
fclose(cur_file->file);
886
free(const_cast<char*>(cur_file->file_name));
900
free((unsigned char*) cur_file->file_name);
887
901
cur_file->file_name= 0;
891
static void free_used_memory()
907
static void free_used_memory(void)
893
912
close_connections();
895
BOOST_FOREACH(var_hash_t::reference i, var_hash)
897
free(i.second->str_val);
898
free(i.second->env_s);
899
if (i.second->alloced)
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)
905
for (size_t i= 0; i < var_reg.size(); i++)
917
vector<st_command *>::iterator iter;
918
for (iter= q_lines.begin() ; iter < q_lines.end() ; iter++)
920
struct st_command * q_line= *iter;
924
for (i= 0; i < 10; i++)
907
926
if (var_reg[i].alloced_len)
908
927
free(var_reg[i].str_val);
910
930
free_all_replace();
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)
1022
1045
fprintf(stderr, "included from %s at line %d\n",
1436
1461
char temp_file_path[FN_REFLEN];
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");
1603
1628
VAR *var_init(VAR *v, const char *name, int name_len, const char *val,
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)
1640
die("Out of memory");
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);
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");
1618
1648
memcpy(tmp_var->name, name, name_len);
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;
1664
void var_free(pair<string, VAR *> v)
1666
free(v.second->str_val);
1667
free(v.second->env_s);
1668
if (v.second->alloced)
1633
1673
VAR* var_from_env(const char *name, const char *def_val)
1635
const char *tmp= getenv(name);
1677
if (!(tmp = getenv(name)))
1638
return var_hash[name] = var_init(0, name, strlen(name), tmp, strlen(tmp));
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));
1641
1687
VAR* var_get(const char *var_name, const char **var_name_end, bool raw,
1642
1688
bool ignore_not_existing)
1646
1693
if (*var_name != '$')
1648
1695
digit = *++var_name - '0';
1664
1711
die("Too long variable name: %s", save_var_name);
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())
1670
1718
char buff[MAX_VAR_NAME_LENGTH+1];
1701
1749
static VAR *var_obtain(const char *name, int len)
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));
2108
2161
internal::fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
2163
if (cur_file == file_stack_end)
2164
die("Source directives are nesting too deep");
2111
if (cur_file == &*file_stack.end())
2112
die("Source directives are nesting too deep");
2113
2166
if (!(cur_file->file= fopen(buff, "r")))
3275
3339
sleep_val= opt_sleep;
3278
usleep(sleep_val * 1000000);
3342
usleep((uint32_t) (sleep_val * 1000000L));
3279
3343
command->last_argument= sleep_end;
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)
3286
char *p= command->first_argument;
3350
char *p= command->first_argument, *name;
3288
3352
die("Missing file name argument");
3290
3354
while (*p && !my_isspace(charset_info,*p))
3321
3385
abort_not_supported_test("Test requires charset '%s'", charset_name);
3324
static void fill_global_error_names()
3326
drizzle_result_st res;
3327
drizzle_return_t ret;
3329
drizzle_con_st *con= &cur_con->con;
3331
global_error_names.clear();
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)
3338
if (ret == DRIZZLE_RETURN_ERROR_CODE)
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);
3346
die("Error running query '%s': %d %s", ds_query.c_str(), ret,
3347
drizzle_con_error(con));
3350
if (drizzle_result_column_count(&res) == 0 ||
3351
drizzle_result_buffer(&res) != DRIZZLE_RETURN_OK)
3353
drizzle_result_free(&res);
3354
die("Query '%s' didn't return a result set", ds_query.c_str());
3357
while ((row= drizzle_row_next(&res)) && row[0])
3360
Concatenate all fields in the first row with tab in between
3361
and assign that string to the $variable
3363
size_t *lengths= drizzle_row_field_sizes(&res);
3366
global_error_names[string(row[0], lengths[0])] = boost::lexical_cast<uint32_t>(string(row[1], lengths[1]));
3368
catch (boost::bad_lexical_cast &ex)
3370
drizzle_result_free(&res);
3371
die("Invalid error_code from Drizzle: %s", ex.what());
3376
drizzle_result_free(&res);
3379
3388
static uint32_t get_errcode_from_name(char *error_name, char *error_end)
3381
3390
size_t err_name_len= error_end - error_name;
3382
3391
string error_name_s(error_name, err_name_len);
3384
ErrorCodes::iterator it= global_error_names.find(error_name_s);
3385
if (it != global_error_names.end())
3388
die("Unknown SQL error name '%s'", error_name_s.c_str());
3393
uint32_t code= global_error_names.getErrorCode(error_name_s);
3396
die("Unknown SQL error name '%s'", error_name_s.c_str());
3392
3401
static void do_get_errcodes(struct st_command *command)
3455
3464
die("The error name definition must start with an uppercase E");
3459
/* Error name string */
3461
to->code.errnum= get_errcode_from_name(p, end);
3470
/* Check that the string passed to str2int only contain digits */
3471
while (*p && p != end)
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);
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);
3485
to->code.errnum= (uint32_t) val;
3462
3486
to->type= ERR_ERRNO;
3466
die ("You must either use the SQLSTATE or built in drizzle error label, numbers are not accepted");
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);
3943
drizzle_con_add_options(&con_slot->con, DRIZZLE_CON_MYSQL);
3922
3945
/* Use default db name */
3923
3946
if (ds_database.length() == 0)
4697
4720
for (i = 0; i < num_fields; i++)
4699
4722
column= drizzle_column_next(res);
4700
if (row[i] && (drizzle_column_type(column) == DRIZZLE_COLUMN_TYPE_TINY))
4702
if (boost::lexical_cast<uint32_t>(row[i]))
4704
if ((drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_UNSIGNED))
4706
append_field(ds, i, column, "YES", 3, false);
4710
append_field(ds, i, column, "TRUE", 4, false);
4715
if ((drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_UNSIGNED))
4717
append_field(ds, i, column, "NO", 2, false);
4721
append_field(ds, i, column, "FALSE", 5, false);
4727
append_field(ds, i, column,
4728
(const char*)row[i], lengths[i], !row[i]);
4723
append_field(ds, i, column,
4724
(const char*)row[i], lengths[i], !row[i]);
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)
4775
replace_append_uint(ds, 1);
4779
replace_append_uint(ds, drizzle_column_max_size(column));
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);
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;
5395
5383
if (in_opt_sleep < -1)
5397
cout << N_("Error: Invalid Value for opt_sleep");
5385
cout<<N_("Error: Invalid Value for opt_sleep");
5400
5388
opt_sleep= in_opt_sleep;
5391
static pair<string, string> parse_password_arg(std::string s)
5393
if (s.find("--password") == 0)
5395
if (s == "--password")
5398
//check if no argument is passed.
5399
return make_pair("password", PASSWORD_SENTINEL);
5402
if (s.substr(10,3) == "=\"\"" || s.substr(10,3) == "=''")
5404
// Check if --password="" or --password=''
5405
return make_pair("password", PASSWORD_SENTINEL);
5408
if(s.substr(10) == "=" && s.length() == 11)
5410
// check if --password= and return a default value
5411
return make_pair("password", PASSWORD_SENTINEL);
5414
if(s.length()>12 && (s[10] == '"' || s[10] == '\''))
5416
// check if --password has quotes, remove quotes and return the value
5417
return make_pair("password", s.substr(11,s.length()-1));
5420
// if all above are false, it implies that --password=value, return value.
5421
return make_pair("password", s.substr(11));
5426
return make_pair(string(""), string(""));
5403
5430
int main(int argc, char **argv)
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(""),
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.")
5488
5515
std::string system_config_dir_client(SYSCONFDIR);
5489
5516
system_config_dir_client.append("/drizzle/client.cnf");
5491
std::string user_config_dir((getenv("XDG_CONFIG_HOME")? getenv("XDG_CONFIG_HOME"):"~/.config"));
5493
if (user_config_dir.compare(0, 2, "~/") == 0)
5495
const char *homedir= getenv("HOME");
5496
if (homedir != NULL)
5497
user_config_dir.replace(0, 1, homedir);
5500
5518
po::variables_map vm;
5502
// Disable allow_guessing
5503
int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
5505
5520
po::store(po::command_line_parser(argc, argv).options(long_options).
5506
style(style).positional(p).extra_parser(parse_password_arg).run(),
5521
positional(p).extra_parser(parse_password_arg).run(), vm);
5509
5523
if (! vm["no-defaults"].as<bool>())
5511
std::string user_config_dir_test(user_config_dir);
5512
user_config_dir_test.append("/drizzle/drizzletest.cnf");
5514
std::string user_config_dir_client(user_config_dir);
5515
user_config_dir_client.append("/drizzle/client.cnf");
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);
5520
ifstream user_client_ifs(user_config_dir_client.c_str());
5521
po::store(parse_config_file(user_client_ifs, client_options), vm);
5523
5528
ifstream system_test_ifs(system_config_dir_test.c_str());
5524
5529
store(parse_config_file(system_test_ifs, test_options), vm);
5531
ifstream user_client_ifs("~/.drizzle/client.cnf");
5532
po::store(parse_config_file(user_client_ifs, client_options), vm);
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);
5539
5547
next_con= connections + 1;
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));
5552
file_stack + (sizeof(file_stack)/sizeof(struct st_test_file)) - 1;
5553
cur_file= file_stack;
5545
5555
/* Init block stack */
5546
5556
memset(block_stack, 0, sizeof(block_stack));
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")))
5585
5595
fprintf(stderr, _("Could not open '%s' for reading: errno = %d"), buff, errno);
5607
5617
unlink(timer_file); /* Ignore error, may not exist */
5610
if (vm.count("protocol"))
5612
std::transform(opt_protocol.begin(), opt_protocol.end(),
5613
opt_protocol.begin(), ::tolower);
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;
5621
cout << _("Error: Unknown protocol") << " '" << opt_protocol << "'" << endl;
5626
5620
if (vm.count("port"))
5628
5622
/* If the port number is > 65535 it is not a valid port
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);
5706
drizzle_con_add_options(&cur_con->con, DRIZZLE_CON_MYSQL);
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);
5707
fill_global_error_names();
5709
5713
/* Use all time until exit if no explicit 'start_timer' */
5710
5714
timer_start= timer_now();
6163
6167
start= buff= (char *)malloc(strlen(from)+1);
6166
6171
uint32_t column_number;
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);
6208
6217
} POINTER_ARRAY;
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);
6217
st_replace *glob_replace= NULL;
6218
// boost::scoped_ptr<st_replace> glob_replace;
6227
struct st_replace *glob_replace= NULL;
6221
6230
Get arguments for replace. The syntax is:
6266
6265
if (my_isspace(charset_info,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);
6369
6371
st_regex substition. At the end of substitutions buf points to the
6370
6372
one containing the final result.
6372
typedef vector<st_regex> regex_arr_t;
6375
6375
char* even_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;
6384
boost::scoped_ptr<st_replace_regex> glob_replace_regex;
6381
struct st_replace_regex *glob_replace_regex= 0;
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
6426
st_replace_regex::st_replace_regex(char* expr)
6423
static struct st_replace_regex* init_replace_regex(char* expr)
6425
struct st_replace_regex* res;
6426
char* buf,*expr_end;
6428
6429
uint32_t expr_len= strlen(expr);
6429
6430
char last_c = 0;
6432
char* buf= new char[expr_len];
6433
char* expr_end= expr + expr_len;
6431
struct st_regex reg;
6433
res=(st_replace_regex*)malloc(sizeof(*res)+expr_len);
6436
my_init_dynamic_array(&res->regex_arr,sizeof(struct st_regex),128,128);
6438
buf= (char*)res + sizeof(*res);
6439
expr_end= expr + expr_len;
6437
6443
/* for each regexp substitution statement */
6438
6444
while (p < expr_end)
6490
regex_arr.push_back(reg);
6497
/* done parsing the statement, now place it in regex_arr */
6498
if (insert_dynamic(&res->regex_arr,(unsigned char*) ®))
6499
die("Out of memory");
6492
odd_buf_len= even_buf_len= buf0_.size();
6493
even_buf= buf0_.data();
6494
odd_buf= buf1_.data();
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;
6500
6510
die("Error parsing replace_regex \"%s\"", expr);
6522
int st_replace_regex::multi_reg_replace(char* val)
6533
static int multi_reg_replace(struct st_replace_regex* r,char* val)
6525
char* out_buf= even_buf;
6526
int* buf_len_p= &even_buf_len;
6536
char* in_buf, *out_buf;
6540
out_buf= r->even_buf;
6541
buf_len_p= &r->even_buf_len;
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++)
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))
6550
get_dynamic(&r->regex_arr,(unsigned char*)&re,i);
6552
if (!reg_replace(&out_buf, buf_len_p, re.pattern, re.replace,
6553
in_buf, re.icase, re.global))
6536
6555
/* if the buffer has been reallocated, make adjustements */
6537
6556
if (save_out_buf != out_buf)
6539
if (save_out_buf == even_buf)
6558
if (save_out_buf == r->even_buf)
6559
r->even_buf= out_buf;
6561
r->odd_buf= out_buf;
6545
6565
if (in_buf == val)
6547
std::swap(in_buf, out_buf);
6548
buf_len_p= (out_buf == even_buf) ? &even_buf_len : &odd_buf_len;
6568
std::swap(in_buf,out_buf);
6570
buf_len_p= (out_buf == r->even_buf) ? &r->even_buf_len :
6575
return (r->buf == 0);
6563
6587
void do_get_replace_regex(struct st_command *command)
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;
6596
void free_replace_regex()
6598
if (glob_replace_regex)
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;
6571
6611
Performs a regex substitution
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;
6675
while(0 >= (rc= pcre_exec(re, NULL, subject.c_str() + current_position, subject.length() - current_position,
6639
rc= pcre_exec(re, NULL, subject.c_str(), subject.length(),
6640
current_position, 0, ovector, 3);
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);
6652
6683
char *new_buf = (char *) malloc(subject.length() + 1);
6673
6704
#define SET_MALLOC_HUNC 64
6674
6705
#define LAST_CHAR_CODE 259
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;
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 */
6697
int find_set(const REP_SET *find);
6698
void free_last_set();
6700
void make_sets_invisible();
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;
6725
typedef struct st_found_set {
6712
6726
uint32_t table_offset;
6713
6727
int found_offset;
6730
typedef struct st_follow {
6719
6732
uint32_t table_offset;
6723
int init_sets(REP_SETS *sets, uint32_t states);
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);
6727
static uint32_t found_sets= 0;
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,
6751
uint32_t start_at_word(char * pos);
6752
uint32_t end_of_word(char * pos);
6754
static uint32_t found_sets=0;
6757
static uint32_t replace_len(char * str)
6731
6759
uint32_t len=0;
6742
/* Return 1 if regexp starts with \b or ends with \b*/
6744
static bool start_at_word(const char *pos)
6746
return ((!memcmp(pos, "\\b",2) && pos[2]) || !memcmp(pos, "\\^", 2));
6749
static bool end_of_word(const char *pos)
6751
const char *end= strchr(pos, '\0');
6752
return (end > pos+2 && !memcmp(end-2, "\\b", 2)) || (end >= pos+2 && !memcmp(end-2, "\\$",2));
6755
6770
/* Init a replace structure for further calls */
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)
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;
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;
6784
REP_SET *set,*start_states,*word_states,*new_set;
6785
FOLLOWS *follow,*follow_ptr;
6787
FOUND_SET *found_set;
6788
REPLACE_STRING *rep_str;
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;
6787
REP_SET *set,*start_states,*word_states,*new_set;
6788
REPLACE_STRING *rep_str;
6789
if (init_sets(&sets, states))
6809
if (init_sets(&sets,states))
6792
vector<FOUND_SET> found_set(max_length * count);
6812
if (!(found_set= (FOUND_SET*) malloc(sizeof(FOUND_SET)*max_length*count)))
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 */
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))))
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++)
6803
6833
if (from[i][0] == '\\' && from[i][1] == '^')
6805
start_states->internal_set_bit(states + 1);
6835
internal_set_bit(start_states,states+1);
6806
6836
if (!from[i][2])
6808
6838
start_states->table_offset=i;
6812
6842
else if (from[i][0] == '\\' && from[i][1] == '$')
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)
6818
6848
start_states->table_offset=i;
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);
6828
start_states->internal_set_bit(states);
6858
internal_set_bit(start_states,states);
6831
for (pos= from[i], len=0; *pos ; pos++)
6860
for (pos=from[i], len=0; *pos ; pos++)
6833
6862
if (*pos == '\\' && *(pos+1))
6874
for (set_nr=0; set_nr < sets.count ; set_nr++)
6903
for (set_nr=0,pos=0 ; set_nr < sets.count ; set_nr++)
6876
6905
set=sets.set+set_nr;
6877
6906
default_state= 0; /* Start from beginning */
6879
6908
/* If end of found-string not found or start-set with current set */
6881
for (i= UINT32_MAX; (i= set->get_next_bit(i)) ;)
6910
for (i= UINT32_MAX; (i=get_next_bit(set,i)) ;)
6883
if (!follow[i].chr && !default_state)
6884
default_state= find_found(&found_set.front(), set->table_offset, set->found_offset+1);
6914
if (! default_state)
6915
default_state= find_found(found_set,set->table_offset,
6916
set->found_offset+1);
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 */
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)) ;)
6894
6927
used_chars[follow[i].chr]=1;
6895
6928
if ((follow[i].chr == SPACE_CHAR && !follow[i+1].chr &&
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 */
6933
new_set->internal_set_bit(i);
6966
internal_set_bit(new_set,i);
6938
6971
new_set->found_len=0; /* Set for testing if first */
6940
for (i= UINT32_MAX; (i= new_set->get_next_bit(i)) ;)
6973
for (i= UINT32_MAX; (i=get_next_bit(new_set,i)) ;)
6942
6975
if ((follow[i].chr == SPACE_CHAR ||
6943
6976
follow[i].chr == END_OF_LINE) && ! chr)
6964
6997
if (bits_set == 1)
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);
6970
set->next[chr] = sets.find_set(new_set);
7005
set->next[chr] = find_set(&sets,new_set);
6973
set->next[chr] = sets.find_set(new_set);
7008
set->next[chr] = find_set(&sets,new_set);
6978
7013
/* Alloc replace structure for the replace-state-machine */
6980
REPLACE *replace= (REPLACE*)malloc(sizeof(REPLACE) * (sets.count)
6981
+ sizeof(REPLACE_STRING) * (found_sets + 1) + sizeof(char*) * count + result_len);
7015
if ((replace=(REPLACE*) malloc(sizeof(REPLACE)*(sets.count)+
7016
sizeof(REPLACE_STRING)*(found_sets+1)+
7017
sizeof(char *)*count+result_len)))
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++)
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)+
7005
7041
for (i=0 ; i < sets.count ; i++)
7075
7113
return make_new_set(sets);
7078
void REP_SETS::free_last_set()
7084
void REP_SETS::free_sets()
7090
void REP_SET::internal_set_bit(uint32_t bit)
7092
bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT);
7095
void REP_SET::internal_clear_bit(uint32_t bit)
7097
bits[bit / WORD_BIT] &= ~ (1 << (bit % WORD_BIT));
7101
void REP_SET::or_bits(const REP_SET *from)
7103
for (uint32_t i= 0 ; i < size_of_bits; i++)
7104
bits[i]|=from->bits[i];
7107
void REP_SET::copy_bits(const REP_SET *from)
7109
memcpy(bits, from->bits, sizeof(uint32_t) * size_of_bits);
7112
int REP_SET::cmp_bits(const REP_SET *set2) const
7114
return memcmp(bits, set2->bits, sizeof(uint32_t) * size_of_bits);
7116
void free_last_set(REP_SETS *sets)
7123
void free_sets(REP_SETS *sets)
7125
free(sets->set_buffer);
7126
free(sets->bit_buffer);
7130
void internal_set_bit(REP_SET *set, uint32_t bit)
7132
set->bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT);
7136
void internal_clear_bit(REP_SET *set, uint32_t bit)
7138
set->bits[bit / WORD_BIT] &= ~ (1 << (bit % WORD_BIT));
7143
void or_bits(REP_SET *to,REP_SET *from)
7145
register uint32_t i;
7146
for (i=0 ; i < to->size_of_bits ; i++)
7147
to->bits[i]|=from->bits[i];
7151
void copy_bits(REP_SET *to,REP_SET *from)
7153
memcpy(to->bits,from->bits,
7154
(size_t) (sizeof(uint32_t) * to->size_of_bits));
7157
int cmp_bits(REP_SET *set1,REP_SET *set2)
7159
return memcmp(set1->bits,set2->bits, sizeof(uint32_t) * set1->size_of_bits);
7117
7163
/* Get next set bit from set. */
7119
int REP_SET::get_next_bit(uint32_t lastpos) const
7165
int get_next_bit(REP_SET *set,uint32_t lastpos)
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);
7125
while (!bits0 && ++start < end)
7167
uint32_t pos,*start,*end,bits;
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);
7173
while (! bits && ++start < end)
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))
7139
7187
free given set, else put in given set in sets and return its
7142
int REP_SETS::find_set(const REP_SET *find)
7190
int find_set(REP_SETS *sets,REP_SET *find)
7145
for (; i < count - 1; i++)
7193
for (i=0 ; i < sets->count-1 ; i++)
7147
if (!set[i].cmp_bits(find))
7195
if (!cmp_bits(sets->set+i,find))
7197
free_last_set(sets);
7160
7208
set->next[] == -1 is reserved for end without replaces.
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)
7166
for (; i < found_sets; 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)
7172
found_set[i].table_offset= table_offset;
7173
found_set[i].found_offset= found_offset;
7218
found_set[i].table_offset=table_offset;
7219
found_set[i].found_offset=found_offset;
7175
return - i - 2; // return new postion
7221
return -i-2; /* return new postion */
7224
/* Return 1 if regexp starts with \b or ends with \b*/
7226
uint32_t start_at_word(char * pos)
7228
return (((!memcmp(pos, "\\b",2) && pos[2]) ||
7229
!memcmp(pos, "\\^", 2)) ? 1 : 0);
7232
uint32_t end_of_word(char * pos)
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;
7178
7239
/****************************************************************************
7251
7312
} /* insert_pointer_name */
7315
/* free pointer array */
7317
void free_pointer_array(POINTER_ARRAY *pa)
7319
if (pa->typelib.count)
7321
pa->typelib.count=0;
7322
free((char*) pa->typelib.type_names);
7323
pa->typelib.type_names=0;
7326
} /* free_pointer_array */
7254
7329
/* Functions that uses replace and replace_regex */
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)
7259
7335
char *v= strdup(val);
7261
if (glob_replace_regex && !glob_replace_regex->multi_reg_replace(v))
7337
if (glob_replace_regex)
7263
v= glob_replace_regex->buf_;
7340
if (!multi_reg_replace(glob_replace_regex, v))
7342
v= glob_replace_regex->buf;
7266
7347
if (glob_replace)
7268
7349
/* Normal replace */
7269
7350
replace_strings_append(glob_replace, ds, v, len);
7272
7354
ds->append(v, len);