aboutsummaryrefslogtreecommitdiffstats
path: root/funcs/func_strings.c
diff options
context:
space:
mode:
authortilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b>2009-04-29 18:53:01 +0000
committertilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b>2009-04-29 18:53:01 +0000
commit8fc2c0f7245703d3dde31d7fa035f3f28c82daeb (patch)
tree972bdf8f96c18f1b9667469307af69385f4a75f3 /funcs/func_strings.c
parent6d9e0aa8817729e7914bb1b3fafe02dc96ae41b5 (diff)
Merge str_substitution branch.
This branch adds additional methods to dialplan functions, whereby the result buffers are now dynamic buffers, which can be expanded to the size of any result. No longer are variable substitutions limited to 4095 bytes of data. In addition, the common case of needing buffers much smaller than that will enable substitution to only take up the amount of memory actually needed. The existing variable substitution routines are still available, but users of those API calls should transition to using the dynamic-buffer APIs. Reviewboard: http://reviewboard.digium.com/r/174/ git-svn-id: http://svn.digium.com/svn/asterisk/trunk@191140 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'funcs/func_strings.c')
-rw-r--r--funcs/func_strings.c163
1 files changed, 141 insertions, 22 deletions
diff --git a/funcs/func_strings.c b/funcs/func_strings.c
index 35211ab85..a2ba285d4 100644
--- a/funcs/func_strings.c
+++ b/funcs/func_strings.c
@@ -343,10 +343,11 @@ AST_THREADSTORAGE(result_buf);
</function>
***/
-static int function_fieldqty(struct ast_channel *chan, const char *cmd,
- char *parse, char *buf, size_t len)
+static int function_fieldqty_helper(struct ast_channel *chan, const char *cmd,
+ char *parse, char *buf, struct ast_str **sbuf, ssize_t len)
{
- char *varsubst, varval[8192], *varval2 = varval;
+ char *varsubst;
+ struct ast_str *str = ast_str_create(16);
int fieldcount = 0;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(varname);
@@ -355,6 +356,10 @@ static int function_fieldqty(struct ast_channel *chan, const char *cmd,
char delim[2] = "";
size_t delim_used;
+ if (!str) {
+ return -1;
+ }
+
AST_STANDARD_APP_ARGS(args, parse);
if (args.delim) {
ast_get_encoded_char(args.delim, delim, &delim_used);
@@ -362,27 +367,47 @@ static int function_fieldqty(struct ast_channel *chan, const char *cmd,
varsubst = alloca(strlen(args.varname) + 4);
sprintf(varsubst, "${%s}", args.varname);
- pbx_substitute_variables_helper(chan, varsubst, varval, sizeof(varval) - 1);
- if (ast_strlen_zero(varval2))
+ ast_str_substitute_variables(&str, 0, chan, varsubst);
+ if (ast_str_strlen(str) == 0) {
fieldcount = 0;
- else {
- while (strsep(&varval2, delim))
+ } else {
+ char *varval = ast_str_buffer(str);
+ while (strsep(&varval, delim)) {
fieldcount++;
+ }
}
} else {
fieldcount = 1;
}
- snprintf(buf, len, "%d", fieldcount);
+ if (sbuf) {
+ ast_str_set(sbuf, len, "%d", fieldcount);
+ } else {
+ snprintf(buf, len, "%d", fieldcount);
+ }
+ ast_free(str);
return 0;
}
+static int function_fieldqty(struct ast_channel *chan, const char *cmd,
+ char *parse, char *buf, size_t len)
+{
+ return function_fieldqty_helper(chan, cmd, parse, buf, NULL, len);
+}
+
+static int function_fieldqty_str(struct ast_channel *chan, const char *cmd,
+ char *parse, struct ast_str **buf, ssize_t len)
+{
+ return function_fieldqty_helper(chan, cmd, parse, NULL, buf, len);
+}
+
static struct ast_custom_function fieldqty_function = {
.name = "FIELDQTY",
.read = function_fieldqty,
+ .read2 = function_fieldqty_str,
};
-static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
+static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, struct ast_str **bufstr, ssize_t len)
{
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(listname);
@@ -392,11 +417,18 @@ static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, ch
const char *orig_list, *ptr;
const char *begin, *cur, *next;
int dlen, flen, first = 1;
- struct ast_str *result = ast_str_thread_get(&result_buf, 16);
+ struct ast_str *result, **result_ptr = &result;
char *delim;
AST_STANDARD_APP_ARGS(args, parse);
+ if (buf) {
+ result = ast_str_thread_get(&result_buf, 16);
+ } else {
+ /* Place the result directly into the output buffer */
+ result_ptr = bufstr;
+ }
+
if (args.argc < 3) {
ast_log(LOG_ERROR, "Usage: LISTFILTER(<listname>,<delimiter>,<fieldvalue>)\n");
return -1;
@@ -416,7 +448,11 @@ static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, ch
/* If the string isn't there, just copy out the string and be done with it. */
if (!(ptr = strstr(orig_list, args.fieldvalue))) {
- ast_copy_string(buf, orig_list, len);
+ if (buf) {
+ ast_copy_string(buf, orig_list, len);
+ } else {
+ ast_str_set(result_ptr, len, "%s", orig_list);
+ }
if (chan) {
ast_channel_unlock(chan);
}
@@ -436,7 +472,9 @@ static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, ch
ast_str_reset(result);
/* Enough space for any result */
- ast_str_make_space(&result, strlen(orig_list) + 1);
+ if (len > -1) {
+ ast_str_make_space(result_ptr, len ? len : strlen(orig_list) + 1);
+ }
begin = orig_list;
next = strstr(begin, delim);
@@ -456,10 +494,10 @@ static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, ch
} else {
/* Copy field to output */
if (!first) {
- ast_str_append(&result, 0, "%s", delim);
+ ast_str_append(result_ptr, len, "%s", delim);
}
- ast_str_append_substr(&result, 0, begin, cur - begin + 1);
+ ast_str_append_substr(result_ptr, len, begin, cur - begin + 1);
first = 0;
begin = cur + dlen;
}
@@ -468,14 +506,27 @@ static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, ch
ast_channel_unlock(chan);
}
- ast_copy_string(buf, ast_str_buffer(result), len);
+ if (buf) {
+ ast_copy_string(buf, ast_str_buffer(result), len);
+ }
return 0;
}
+static int listfilter_read(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
+{
+ return listfilter(chan, cmd, parse, buf, NULL, len);
+}
+
+static int listfilter_read2(struct ast_channel *chan, const char *cmd, char *parse, struct ast_str **buf, ssize_t len)
+{
+ return listfilter(chan, cmd, parse, NULL, buf, len);
+}
+
static struct ast_custom_function listfilter_function = {
.name = "LISTFILTER",
- .read = listfilter,
+ .read = listfilter_read,
+ .read2 = listfilter_read2,
};
static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
@@ -679,16 +730,15 @@ static int array(struct ast_channel *chan, const char *cmd, char *var,
static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
struct ast_var_t *newvar;
- int plen;
- char prefix[80];
- snprintf(prefix, sizeof(prefix), HASH_PREFIX, data);
- plen = strlen(prefix);
+ struct ast_str *prefix = ast_str_alloca(80);
+ ast_str_set(&prefix, -1, HASH_PREFIX, data);
memset(buf, 0, len);
+
AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) {
- if (strncasecmp(prefix, ast_var_name(newvar), plen) == 0) {
+ if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
/* Copy everything after the prefix */
- strncat(buf, ast_var_name(newvar) + plen, len - strlen(buf) - 1);
+ strncat(buf, ast_var_name(newvar) + ast_str_strlen(prefix), len - strlen(buf) - 1);
/* Trim the trailing ~ */
buf[strlen(buf) - 1] = ',';
}
@@ -698,6 +748,29 @@ static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data,
return 0;
}
+static int hashkeys_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
+{
+ struct ast_var_t *newvar;
+ struct ast_str *prefix = ast_str_alloca(80);
+ char *tmp;
+
+ ast_str_set(&prefix, -1, HASH_PREFIX, data);
+
+ AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) {
+ if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
+ /* Copy everything after the prefix */
+ ast_str_append(buf, len, "%s", ast_var_name(newvar) + ast_str_strlen(prefix));
+ /* Trim the trailing ~ */
+ tmp = ast_str_buffer(*buf);
+ tmp[ast_str_strlen(*buf) - 1] = ',';
+ }
+ }
+ /* Trim the trailing comma */
+ tmp = ast_str_buffer(*buf);
+ tmp[ast_str_strlen(*buf) - 1] = '\0';
+ return 0;
+}
+
static int hash_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
{
char varname[256];
@@ -773,6 +846,7 @@ static struct ast_custom_function hash_function = {
static struct ast_custom_function hashkeys_function = {
.name = "HASHKEYS",
.read = hashkeys_read,
+ .read2 = hashkeys_read2,
};
static struct ast_custom_function array_function = {
@@ -824,6 +898,7 @@ static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf,
static struct ast_custom_function len_function = {
.name = "LEN",
.read = len,
+ .read_max = 12,
};
static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse,
@@ -915,9 +990,23 @@ static int function_eval(struct ast_channel *chan, const char *cmd, char *data,
return 0;
}
+static int function_eval2(struct ast_channel *chan, const char *cmd, char *data,
+ struct ast_str **buf, ssize_t buflen)
+{
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
+ return -1;
+ }
+
+ ast_str_substitute_variables(buf, buflen, chan, data);
+
+ return 0;
+}
+
static struct ast_custom_function eval_function = {
.name = "EVAL",
.read = function_eval,
+ .read2 = function_eval2,
};
static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
@@ -969,9 +1058,24 @@ static int string_toupper(struct ast_channel *chan, const char *cmd, char *data,
return 0;
}
+static int string_toupper2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
+{
+ char *bufptr, *dataptr = data;
+
+ if (buflen > -1) {
+ ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
+ }
+ bufptr = ast_str_buffer(*buf);
+ while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = toupper(*dataptr++)));
+ ast_str_update(*buf);
+
+ return 0;
+}
+
static struct ast_custom_function toupper_function = {
.name = "TOUPPER",
.read = string_toupper,
+ .read2 = string_toupper2,
};
static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
@@ -983,9 +1087,24 @@ static int string_tolower(struct ast_channel *chan, const char *cmd, char *data,
return 0;
}
+static int string_tolower2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
+{
+ char *bufptr, *dataptr = data;
+
+ if (buflen > -1) {
+ ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
+ }
+ bufptr = ast_str_buffer(*buf);
+ while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = tolower(*dataptr++)));
+ ast_str_update(*buf);
+
+ return 0;
+}
+
static struct ast_custom_function tolower_function = {
.name = "TOLOWER",
.read = string_tolower,
+ .read2 = string_tolower2,
};
static int array_remove(struct ast_channel *chan, const char *cmd, char *var, char *buf, size_t len, int beginning)