optimized str_replace_str

This commit is contained in:
Nikos Mavrogiannopoulos
2015-10-29 22:52:36 +01:00
parent 7d4a8f1551
commit 12208b4d3d
4 changed files with 75 additions and 48 deletions

View File

@@ -31,6 +31,7 @@
#include <str.h>
#include <common.h>
static
int replace_cmd(struct main_server_st* s, proc_st *proc,
char **cmd, const char* pattern,
@@ -38,6 +39,13 @@ int replace_cmd(struct main_server_st* s, proc_st *proc,
{
str_st str;
int ret;
str_rep_tab tab[5];
STR_TAB_SET(0, "%{R}", route);
STR_TAB_SET(1, "%R", route);
STR_TAB_SET(2, "%{D}", dev);
STR_TAB_SET(3, "%D", dev);
STR_TAB_TERM(4);
str_init(&str, proc);
@@ -45,20 +53,7 @@ int replace_cmd(struct main_server_st* s, proc_st *proc,
if (ret < 0)
return ERR_MEM;
ret = str_replace_str(&str, "%{R}", route);
if (ret < 0)
goto fail;
ret = str_replace_str(&str, "%{D}", dev);
if (ret < 0)
goto fail;
/* The old compatibility strings */
ret = str_replace_str(&str, "%R", route);
if (ret < 0)
goto fail;
ret = str_replace_str(&str, "%D", dev);
ret = str_replace_str(&str, tab);
if (ret < 0)
goto fail;

View File

@@ -149,41 +149,61 @@ str_append_printf(str_st *dest, const char *fmt, ...)
return len;
}
int str_replace_str(str_st *str, const char *what, const char *with)
int str_replace_str(str_st *str, const str_rep_tab *tab)
{
uint8_t *p, *final;
unsigned what_len, final_len;
int ret;
uint8_t *p;
const str_rep_tab *ptab;
unsigned length;
char *final;
unsigned final_len;
int ret, pos;
what_len = strlen(what);
p = str->data;
pos = 0;
do {
p = memchr(p, '%', str->length - pos);
if (p == NULL)
break;
p = memmem(str->data, str->length, what, what_len);
if (p == NULL)
return 0;
pos = (ptrdiff_t)(p-str->data);
p += what_len;
final_len = str->length - (ptrdiff_t)(p-str->data);
length = str->length - pos;
final = talloc_memdup(str->allocd, p, final_len);
if (final == NULL)
return -1;
ptab = tab;
do {
if (length >= ptab->pattern_length &&
memcmp(ptab->pattern, p, ptab->pattern_length) == 0) {
/* replace */
final_len = length - ptab->pattern_length;
final = talloc_memdup(str->allocd, p+ptab->pattern_length, final_len);
if (final == NULL)
return -1;
str->length -= final_len + what_len;
str->length -= final_len + ptab->pattern_length;
ret = str_append_str(str, ptab->rep_val);
if (ret < 0) {
talloc_free(final);
return ret;
}
ret = str_append_str(str, with);
if (ret < 0) {
talloc_free(final);
return ret;
}
ret = str_append_data(str, final, final_len);
talloc_free(final);
if (ret < 0) {
return ret;
}
break;
}
ptab++;
ret = str_append_data(str, final, final_len);
talloc_free(final);
if (ptab->pattern == NULL) {
/* not found */
return -1;
}
} while(1);
if (ret < 0) {
return ret;
}
p = &str->data[pos];
} while(pos < str->length);
/* allow multiple replacements */
return str_replace_str(str, what, with);
return 0;
}

View File

@@ -26,6 +26,19 @@
#include <config.h>
#include <stdint.h>
#define STR_TAB_SET(i,pat,val) { \
tab[i].pattern = pat; \
tab[i].pattern_length = sizeof(pat)-1; \
tab[i].rep_val = val; \
}
#define STR_TAB_TERM(i) tab[i].pattern = NULL
typedef struct {
const char *pattern;
unsigned pattern_length;
const char *rep_val;
} str_rep_tab;
typedef struct {
uint8_t *allocd; /* pointer to allocated data */
uint8_t *data; /* API: pointer to data to copy from */
@@ -55,7 +68,7 @@ inline static void str_reset(str_st * buf)
int str_append_printf(str_st *dest, const char *fmt, ...);
int str_append_str(str_st *, const char *str);
int str_replace_str(str_st *, const char *what, const char *with);
int str_replace_str(str_st *, const str_rep_tab *tab);
int str_append_data(str_st *, const void *data, size_t data_size);
int str_append_size(str_st *, size_t data_size);
int str_append_data_prefix1(str_st *, const void *data, size_t data_size);

View File

@@ -1250,6 +1250,11 @@ char *replace_vals(worker_st *ws, const char *txt)
{
str_st str;
int ret;
str_rep_tab tab[3];
STR_TAB_SET(0, "%{U}", ws->username);
STR_TAB_SET(1, "%{G}", ws->groupname);
STR_TAB_TERM(2);
str_init(&str, ws);
@@ -1257,13 +1262,7 @@ char *replace_vals(worker_st *ws, const char *txt)
if (ret < 0)
return NULL;
ret = str_replace_str(&str, "%{U}", ws->username);
if (ret < 0) {
str_clear(&str);
return NULL;
}
ret = str_replace_str(&str, "%{G}", ws->groupname);
ret = str_replace_str(&str, tab);
if (ret < 0) {
str_clear(&str);
return NULL;