add quote split string

This commit is contained in:
ubuntu14 2016-04-14 22:39:11 +08:00
parent ecc0869cce
commit a6f78cc0b0
12 changed files with 371 additions and 31 deletions

View File

@ -1,4 +1,7 @@
6) 2016.4.14
6.1) feature: 增加了在集群模式下 CONFIG 命令的支持
5) 2016.4.12
5.1) feature: redis_dump 类支持优先从集群中的从节点获取命令,以减轻对主节点的压力
5.2) feature: 对于可以使用从节点获取结果的操作,可以优先使用从节点

View File

@ -100,6 +100,9 @@ void redis_commands::help(void)
" \033[1;36;40mredis_addr\033[0m\r\n");
printf("> \033[1;33;40mdbsize\033[0m\r\n");
printf("> \033[1;33;40mnodes\033[0m\r\n");
printf("> \033[1;33;40mconfig set|get parameter\033[0m\r\n");
printf("> \033[1;33;40mconfig rewrite\033[0m\r\n");
printf("> \033[1;33;40mconfig resetstat\033[0m\r\n");
#else
printf("> keys pattern limit\r\n");
printf("> get [:limit] parameter ...\r\n");
@ -110,6 +113,9 @@ void redis_commands::help(void)
printf("> server redis_addr\r\n");
printf("> dbsize\r\n");
printf("> nodes\r\n");
printf("> config set|get parameter\r\n");
printf("> config rewrite\r\n");
printf("> config resetstat\r\n");
#endif
}
@ -135,7 +141,8 @@ void redis_commands::run(void)
continue;
}
std::vector<acl::string>& tokens = buf.split2(" \t");
std::vector<acl::string>& tokens = buf.quote_split2(" \t");
acl::string& cmd = tokens[0];
cmd.lower();
@ -159,6 +166,8 @@ void redis_commands::run(void)
check_ttl(tokens);
else if (cmd == "dbsize")
get_dbsize(tokens);
else if (cmd == "config")
config(tokens);
#ifdef HAS_READLINE
else if (cmd == "clear" || cmd == "cl")
{
@ -827,14 +836,7 @@ void redis_commands::request(const std::vector<acl::string>& tokens)
if (result == NULL)
{
printf("request error: %s\r\n", cmd.result_error());
for (std::vector<acl::string>::const_iterator cit =
tokens.begin(); cit != tokens.end(); ++cit)
{
if (cit == tokens.begin())
printf("%s", (*cit).c_str());
else
printf(" %s", (*cit).c_str());
}
show_request(tokens);
printf("\r\n");
return;
}
@ -842,7 +844,7 @@ void redis_commands::request(const std::vector<acl::string>& tokens)
show_result(*result);
}
void redis_commands::show_result(const acl::redis_result& result)
bool redis_commands::show_result(const acl::redis_result& result)
{
acl::string buf;
size_t size;
@ -856,7 +858,7 @@ void redis_commands::show_result(const acl::redis_result& result)
break;
case acl::REDIS_RESULT_ERROR:
printf("-%s\r\n", result.get_error());
break;
return false;
case acl::REDIS_RESULT_STATUS:
printf("+%s\r\n", result.get_status());
break;
@ -882,10 +884,99 @@ void redis_commands::show_result(const acl::redis_result& result)
break;
case acl::REDIS_RESULT_UNKOWN:
printf("unknown type: %d\r\n", (int) type);
break;
default:
printf("unknown type: %d\r\n", (int) type);
break;
return false;
}
return true;
}
void redis_commands::show_request(const std::vector<acl::string>& tokens)
{
for (std::vector<acl::string>::const_iterator cit =
tokens.begin(); cit != tokens.end(); ++cit)
{
if (cit == tokens.begin())
printf("%s", (*cit).c_str());
else
printf(" \"%s\"", (*cit).c_str());
}
}
void redis_commands::config_usage(void)
{
logger_error("> usage: config get parameter");
logger_error("> usage: config set parameter");
logger_error("> usage: config rewrite");
logger_error("> usage: config resetstat");
}
void redis_commands::config(const std::vector<acl::string>& tokens)
{
if (tokens.size() < 2)
{
config_usage();
return;
}
acl::redis_client client(addr_, conn_timeout_, rw_timeout_);
client.set_password(passwd_);
acl::redis redis(&client);
std::vector<const acl::redis_node*> nodes;
redis_util::get_all_nodes(redis, nodes);
if (nodes.empty())
{
logger_error("no node of the cluster: %s", addr_.c_str());
return;
}
for (std::vector<const acl::redis_node*>::const_iterator cit
= nodes.begin(); cit != nodes.end(); ++cit)
{
const char* addr = (*cit)->get_addr();
if (addr == NULL || *addr == 0)
{
logger_error("addr NULL");
continue;
}
config(addr, tokens);
}
}
void redis_commands::config(const char* addr,
const std::vector<acl::string>& tokens)
{
if (tokens.size() < 2)
{
config_usage();
return;
}
request_one(addr, tokens);
}
void redis_commands::request_one(const char* addr,
const std::vector<acl::string>& tokens)
{
acl::redis_client client(addr, conn_timeout_, rw_timeout_);
client.set_password(passwd_);
acl::redis redis(&client);
const acl::redis_result* result = redis.request(tokens);
if (result == NULL)
{
printf("request error: %s\r\n", redis.result_error());
show_request(tokens);
printf("\r\n");
}
else
{
if (show_result(*result) == false)
{
printf("request error\r\n");
show_request(tokens);
printf("\r\n");
}
}
}

View File

@ -50,5 +50,13 @@ private:
void check_ttl(const std::vector<acl::string>& tokens);
void get_dbsize(const std::vector<acl::string>& tokens);
void request(const std::vector<acl::string>& tokens);
void show_result(const acl::redis_result& result);
bool show_result(const acl::redis_result& result);
void show_request(const std::vector<acl::string>& tokens);
void config(const std::vector<acl::string>& tokens);
void config(const char* addr, const std::vector<acl::string>& tokens);
void config_usage(void);
void request_one(const char* addr,
const std::vector<acl::string>& tokens);
};

View File

@ -260,3 +260,39 @@ const std::map<acl::string, acl::redis_node*>* redis_util::get_masters2(
return masters;
}
void redis_util::get_all_nodes(acl::redis& redis,
std::vector<const acl::redis_node*>& nodes)
{
const std::map<acl::string, acl::redis_node*>* masters
= get_masters(redis);
if (masters == NULL)
{
logger_error("get_masters NULL");
return;
}
for (std::map<acl::string, acl::redis_node*>::const_iterator cit
= masters->begin(); cit != masters->end(); ++cit)
{
add_slaves(cit->second, nodes);
}
}
void redis_util::add_slaves(const acl::redis_node* node,
std::vector<const acl::redis_node*>& nodes)
{
if (node == NULL)
return;
nodes.push_back(node);
const std::vector<acl::redis_node*>* slaves = node->get_slaves();
if (slaves == NULL)
return;
for (std::vector<acl::redis_node*>::const_iterator cit
= slaves->begin(); cit != slaves->end(); ++cit)
{
add_slaves(*cit, nodes);
}
}

View File

@ -42,7 +42,14 @@ public:
static void get_nodes(acl::redis& redis, bool prefer_master,
std::vector<acl::redis_node*>& nodes);
// get all the nodes of the cluster
static void get_all_nodes(acl::redis& redis,
std::vector<const acl::redis_node*>& nodes);
private:
static const std::map<acl::string, acl::redis_node*>*
get_masters2(acl::redis&);
static void add_slaves(const acl::redis_node* node,
std::vector<const acl::redis_node*>& nodes);
};

View File

@ -1,6 +1,10 @@
修改历史列表:
------------------------------------------------------------------------
542) 2016.4.14
542.1) feature: acl_argv_split.c 新增字符串分隔函数 acl_argv_quote_split 允许
在对字符串进行分隔时,不破坏被单引号/双引号引用的字符串
541) 2016.3.29
541.1) bugfix: acl_vstream.c 中针对 stdin, stdout, stderr 需要做特殊处理

View File

@ -173,6 +173,27 @@ ACL_API ACL_ARGV *acl_argv_split_append(ACL_ARGV *argvp, const char *str,
ACL_API ACL_ARGV *acl_argv_splitn_append(ACL_ARGV *argvp, const char *str,
const char *delim, size_t n);
/**
* "" ''
*
* @param str {const char*}
* @param delim {const char*}
* @return {ACL_ARGV*}
*/
ACL_API ACL_ARGV *acl_argv_quote_split(const char *str, const char *delim);
/**
* "" ''
*
* @param str {const char*}
* @param delim {const char*}
* @param dbuf {ACL_DBUF_POOL*}
*
* @return {ACL_ARGV*}
*/
ACL_API ACL_ARGV *acl_argv_quote_split4(const char *str, const char *delim,
ACL_DBUF_POOL *dbuf);
#define ACL_ARGV_END ((char *) 0)
# ifdef __cplusplus

View File

@ -1,5 +1,39 @@
#include "lib_acl.h"
static void quote_split(const char* str, const char* delim)
{
ACL_ITER iter;
ACL_ARGV *tokens = acl_argv_quote_split(str, delim);
printf("---------------------------------------------\r\n");
printf("str = [%s], delim = [%s]\r\n", str, delim);
acl_foreach(iter, tokens) {
const char* ptr = (const char*) iter.data;
printf("%s\r\n", ptr);
}
acl_argv_free(tokens);
}
static void test_quote_split(void)
{
struct {
const char* str;
const char* delim;
} data[] = {
{ "hello world", " \t" },
{ "\t hello\' world\"", "\t " },
{ "hi \"hello world\"", "\t " },
{ "\t 'myname is zsx.' \"what\'s your name?\" Good! ", "\t " },
{ "name = \"zsx xsz\", name2 = 'xsz,= zsx'", "\t =," },
{ NULL, NULL },
};
int i;
for (i = 0; data[i].str != NULL && data[i].delim; i++)
quote_split(data[i].str, data[i].delim);
}
int main(void)
{
char *src = acl_mystrdup("hello \tworld! you're welcome to China!");
@ -41,5 +75,10 @@ int main(void)
printf("buf: %s\r\n", acl_vstring_str(buf));
acl_vstring_free(buf);
printf("Enter any key to continue ...\r\n");
getchar();
test_quote_split();
return 0;
}

View File

@ -11,24 +11,24 @@
#include "stdlib/acl_mymalloc.h"
#include "stdlib/acl_argv.h"
#include "stdlib/acl_vstring.h"
#include "stdlib/acl_mystring.h"
#endif
/* acl_argv_split - split string into token array */
ACL_ARGV *acl_argv_split(const char *str, const char *delim)
ACL_ARGV *acl_argv_split(const char *str, const char *delim)
{
return acl_argv_split3(str, delim, NULL);
}
ACL_ARGV *acl_argv_split3(const char *str, const char *delim,
ACL_ARGV *acl_argv_split3(const char *str, const char *delim,
ACL_DBUF_POOL *dbuf)
{
ACL_ARGV *argvp = acl_argv_alloc2(1, dbuf);
char *saved_string = dbuf ?
acl_dbuf_pool_strdup(dbuf, str) :
acl_mystrdup(str);
ACL_ARGV *argvp = acl_argv_alloc2(1, dbuf);
char *saved_string =
dbuf ? acl_dbuf_pool_strdup(dbuf, str) : acl_mystrdup(str);
char *bp = saved_string;
char *arg;
@ -44,18 +44,17 @@ ACL_ARGV *acl_argv_split3(const char *str, const char *delim,
/* acl_argv_splitn - split string into token array with max items */
ACL_ARGV *acl_argv_splitn(const char *str, const char *delim, size_t n)
ACL_ARGV *acl_argv_splitn(const char *str, const char *delim, size_t n)
{
return acl_argv_splitn4(str, delim, n, NULL);
}
ACL_ARGV *acl_argv_splitn4(const char *str, const char *delim,
ACL_ARGV *acl_argv_splitn4(const char *str, const char *delim,
size_t n, ACL_DBUF_POOL *dbuf)
{
ACL_ARGV *argvp = acl_argv_alloc2(n > 0 ? (int) n : 1, dbuf);
ACL_ARGV *argvp = acl_argv_alloc2(n > 0 ? (int) n : 1, dbuf);
char *saved_string = dbuf ?
acl_dbuf_pool_strdup(dbuf, str) :
acl_mystrdup(str);
acl_dbuf_pool_strdup(dbuf, str) : acl_mystrdup(str);
char *bp = saved_string;
char *arg;
@ -71,12 +70,11 @@ ACL_ARGV *acl_argv_splitn4(const char *str, const char *delim,
/* acl_argv_split_append - split string into token array, append to array */
ACL_ARGV *acl_argv_split_append(ACL_ARGV *argvp, const char *str,
ACL_ARGV *acl_argv_split_append(ACL_ARGV *argvp, const char *str,
const char *delim)
{
char *saved_string = argvp->dbuf ?
acl_dbuf_pool_strdup(argvp->dbuf, str) :
acl_mystrdup(str);
acl_dbuf_pool_strdup(argvp->dbuf, str) : acl_mystrdup(str);
char *bp = saved_string;
char *arg;
@ -93,12 +91,11 @@ ACL_ARGV *acl_argv_split_append(ACL_ARGV *argvp, const char *str,
/* acl_argv_splitn_append - split string into token array, append to
* array with max items */
ACL_ARGV *acl_argv_splitn_append(ACL_ARGV *argvp, const char *str,
ACL_ARGV *acl_argv_splitn_append(ACL_ARGV *argvp, const char *str,
const char *delim, size_t n)
{
char *saved_string = argvp->dbuf ?
acl_dbuf_pool_strdup(argvp->dbuf, str) :
acl_mystrdup(str);
acl_dbuf_pool_strdup(argvp->dbuf, str) : acl_mystrdup(str);
char *bp = saved_string;
char *arg;
@ -111,3 +108,79 @@ ACL_ARGV *acl_argv_splitn_append(ACL_ARGV *argvp, const char *str,
acl_myfree(saved_string);
return argvp;
}
ACL_ARGV *acl_argv_quote_split(const char *str, const char *delim)
{
return acl_argv_quote_split4(str, delim, NULL);
}
ACL_ARGV *acl_argv_quote_split4(const char *str, const char *delim,
ACL_DBUF_POOL *dbuf)
{
ACL_ARGV *argvp = acl_argv_alloc2(1, dbuf);
char *saved_string =
dbuf ? acl_dbuf_pool_strdup(dbuf, str) : acl_mystrdup(str);
char *bp = saved_string;
int ch, quote = 0, backslash = 0;
ACL_VSTRING *buf = acl_vstring_dbuf_alloc(dbuf, 128);
#define ADDCH ACL_VSTRING_ADDCH
#define TERM ACL_VSTRING_TERMINATE
#define LEN ACL_VSTRING_LEN
#define STR acl_vstring_str
#define RESET ACL_VSTRING_RESET
while ((ch = *bp) != 0) {
if (quote) {
if (backslash) {
ADDCH(buf, ch);
TERM(buf);
backslash = 0;
} else if (ch == '\\')
backslash = 1;
else if (ch == quote) {
quote = 0;
if (LEN(buf) > 0) {
acl_argv_add(argvp, STR(buf), NULL);
RESET(buf);
}
} else {
ADDCH(buf, ch);
TERM(buf);
}
} else if (backslash) {
ADDCH(buf, ch);
TERM(buf);
backslash = 0;
} else if (ch == '\\')
backslash = 1;
else if (ch == '\'' || ch == '\"')
quote = ch;
else if (strchr(delim, ch) != NULL) {
if (LEN(buf) > 0) {
acl_argv_add(argvp, STR(buf), NULL);
RESET(buf);
}
} else {
ADDCH(buf, ch);
TERM(buf);
}
bp++;;
}
if (LEN(buf) > 0)
acl_argv_add(argvp, STR(buf), NULL);
acl_argv_terminate(argvp);
acl_vstring_free(buf);
if (dbuf)
acl_dbuf_pool_free(dbuf, saved_string);
else
acl_myfree(saved_string);
return argvp;
}

View File

@ -1,6 +1,10 @@
修改历史列表:
-----------------------------------------------------------------------
421) 2016.4.14
421.1) feature: string 类增加两个方法 quote_split/quote_split2对 lib_acl C
库中新增的字符串分割函数进行封装
420) 2016.4.6
420.1) feature&safety: redis_command::run 中当发现 used_ > 0 时会强制调用 clear
来释放上次操作时临时创建的内存,以免用户反复使用该命令时忘记调用 clear

View File

@ -837,6 +837,24 @@ public:
*/
std::vector<string>& split2(const char* sep);
/**
* /
*
* @param sep {const char*}
* @return {std::list<string>&} list
*
*/
std::list<string>& quote_split(const char* sep);
/**
* /
*
* @param sep {const char*}
* @return {std::vector<string>&} vector
*
*/
std::vector<string>& quote_split2(const char* sep);
/**
* '=' name/value
* '=' TAB

View File

@ -1003,6 +1003,42 @@ std::vector<acl::string>& string::split2(const char* sep)
return *vector_tmp_;
}
std::list<acl::string>& string::quote_split(const char* sep)
{
ACL_ARGV *argv = acl_argv_quote_split(STR(vbf_), sep);
ACL_ITER it;
if (list_tmp_ == NULL)
list_tmp_ = NEW std::list<acl::string>;
else
list_tmp_->clear();
acl_foreach(it, argv)
{
char* ptr = (char*) it.data;
list_tmp_->push_back(ptr);
}
acl_argv_free(argv);
return *list_tmp_;
}
std::vector<acl::string>& string::quote_split2(const char* sep)
{
ACL_ARGV *argv = acl_argv_quote_split(STR(vbf_), sep);
ACL_ITER it;
if (vector_tmp_ == NULL)
vector_tmp_ = NEW std::vector<acl::string>;
else
vector_tmp_->clear();
acl_foreach(it, argv)
{
char* ptr = (char*) it.data;
vector_tmp_->push_back(ptr);
}
acl_argv_free(argv);
return *vector_tmp_;
}
std::pair<acl::string, acl::string>& string::split_nameval()
{
char *name, *value;