--- funcs/func_strings.c.orig 2010-03-10 17:48:33.000000000 -0300
+++ funcs/func_strings.c 2010-07-08 12:50:11.000000000 -0300
@@ -40,6 +40,7 @@
#include "asterisk/localtime.h"
AST_THREADSTORAGE(result_buf);
+AST_THREADSTORAGE(tmp_buf);
/*** DOCUMENTATION
@@ -91,6 +92,37 @@
\
+
+
+ Replace a set of characters in a given string with another character.
+
+
+
+
+
+
+
+ Iterates through a string replacing all the find-chars with
+ replace-char. replace-char may be either
+ empty or contain one character. If empty, all find-chars will be
+ deleted from the output.
+ The replacement only occurs in the output. The original variable is not
+ altered.
+
+
+
+
+ Pass the given argument back as a value.
+
+
+
+
+
+ Literally returns the given string. The intent is to permit
+ other dialplan functions which take a variable name as an argument to be able to take a literal
+ string, instead.
+
+
Check string against a regular expression.
@@ -287,6 +319,76 @@
Example: ${CSV_QUOTE("a,b" 123)} will return """a,b"" 123"
+
+
+ Removes and returns the first item off of a variable containing delimited text
+
+
+
+
+
+
+ Example:
+ exten => s,1,Set(array=one,two,three)
+ exten => s,n,While($["${SET(var=${SHIFT(array)})}" != ""])
+ exten => s,n,NoOp(var is ${var})
+ exten => s,n,EndWhile
+ This would iterate over each value in array, left to right, and
+ would result in NoOp(var is one), NoOp(var is two), and
+ NoOp(var is three) being executed.
+
+
+
+
+
+ Removes and returns the last item off of a variable containing delimited text
+
+
+
+
+
+
+ Example:
+ exten => s,1,Set(array=one,two,three)
+ exten => s,n,While($["${SET(var=${POP(array)})}" != ""])
+ exten => s,n,NoOp(var is ${var})
+ exten => s,n,EndWhile
+ This would iterate over each value in array, right to left, and
+ would result in NoOp(var is three), NoOp(var is two), and
+ NoOp(var is one) being executed.
+
+
+
+
+
+ Appends one or more values to the end of a variable containing delimited text
+
+
+
+
+
+
+ Example: Set(PUSH(array)=one,two,three) would append one,
+ two, and three to the end of the values stored in the variable
+ "array".
+
+
+
+
+
+ Inserts one or more values to the beginning of a variable containing delimited text
+
+
+
+
+
+
+ Example: Set(UNSHIFT(array)=one,two,three) would insert one,
+ two, and three before the values stored in the variable
+ "array".
+
+
+
***/
static int function_fieldqty(struct ast_channel *chan, const char *cmd,
@@ -505,8 +607,77 @@
.read = filter,
};
-static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
- size_t len)
+static int replace(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(varname);
+ AST_APP_ARG(find);
+ AST_APP_ARG(replace);
+ );
+ char *strptr, *varsubst;
+ struct ast_str *str = ast_str_thread_get(&result_buf, 16);
+ char find[256]; /* Only 256 characters possible */
+ char replace[2] = "";
+ size_t unused;
+
+ AST_STANDARD_APP_ARGS(args, data);
+
+ if (!str) {
+ return -1;
+ }
+
+ if (args.argc < 2) {
+ ast_log(LOG_ERROR, "Usage: %s(,[,])\n", cmd);
+ return -1;
+ }
+
+ /* Decode escapes */
+ ast_get_encoded_str(args.find, find, sizeof(find));
+ ast_get_encoded_char(args.replace, replace, &unused);
+
+ if (ast_strlen_zero(find) || ast_strlen_zero(args.varname)) {
+ ast_log(LOG_ERROR, "The characters to search for and the variable name must not be empty.\n");
+ return -1;
+ }
+
+ varsubst = alloca(strlen(args.varname) + 4);
+ sprintf(varsubst, "${%s}", args.varname);
+ ast_str_substitute_variables(&str, 0, chan, varsubst);
+
+ if (!ast_str_strlen(str)) {
+ /* Blank, nothing to replace */
+ return -1;
+ }
+
+ ast_debug(3, "String to search: (%s)\n", ast_str_buffer(str));
+ ast_debug(3, "Characters to find: (%s)\n", find);
+ ast_debug(3, "Character to replace with: (%s)\n", replace);
+
+ for (strptr = ast_str_buffer(str); *strptr; strptr++) {
+ /* buf is already a mutable buffer, so we construct the result
+ * directly there */
+ if (strchr(find, *strptr)) {
+ if (ast_strlen_zero(replace)) {
+ /* Remove character */
+ strcpy(strptr, strptr + 1); /* SAFE */
+ strptr--;
+ } else {
+ /* Replace character */
+ *strptr = *replace;
+ }
+ }
+ }
+
+ snprintf(buf, len, "%s", ast_str_buffer(str));
+ return 0;
+}
+
+static struct ast_custom_function replace_function = {
+ .name = "REPLACE",
+ .read = replace,
+};
+
+static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
{
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(null);
@@ -997,12 +1168,140 @@
.read = string_tolower,
};
+static int shift_pop(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+#define beginning (cmd[0] == 'S') /* SHIFT */
+ char *after, delimiter[2] = ",", *varsubst;
+ size_t unused;
+ struct ast_str *before = ast_str_thread_get(&result_buf, 16);
+ char *(*search_func)(const char *s, int c) = (beginning ? strchr : strrchr);
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(var);
+ AST_APP_ARG(delimiter);
+ );
+
+ if (!before) {
+ return -1;
+ }
+
+ AST_STANDARD_APP_ARGS(args, data);
+
+ if (ast_strlen_zero(args.var)) {
+ ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
+ return -1;
+ }
+
+ varsubst = alloca(strlen(args.var) + 4);
+ sprintf(varsubst, "${%s}", args.var);
+ ast_str_substitute_variables(&before, 0, chan, varsubst);
+
+ if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
+ ast_get_encoded_char(args.delimiter, delimiter, &unused);
+ }
+
+ if (!ast_str_strlen(before)) {
+ /* Nothing to pop */
+ return -1;
+ }
+
+ if (!(after = search_func(ast_str_buffer(before), delimiter[0]))) {
+ /* Only one entry in array */
+ snprintf(buf, len, "%s", ast_str_buffer(before));
+ pbx_builtin_setvar_helper(chan, args.var, "");
+ } else {
+ *after++ = '\0';
+ snprintf(buf, len, "%s", beginning ? ast_str_buffer(before) : after);
+ pbx_builtin_setvar_helper(chan, args.var, beginning ? after : ast_str_buffer(before));
+ }
+
+ return 0;
+#undef beginning
+}
+
+static struct ast_custom_function shift_function = {
+ .name = "SHIFT",
+ .read = shift_pop,
+};
+
+static struct ast_custom_function pop_function = {
+ .name = "POP",
+ .read = shift_pop,
+};
+
+static int unshift_push(struct ast_channel *chan, const char *cmd, char *data, const char *new_value)
+{
+#define beginning (cmd[0] == 'U') /* UNSHIFT */
+ char delimiter[2] = ",", *varsubst;
+ size_t unused;
+ struct ast_str *buf, *previous_value;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(var);
+ AST_APP_ARG(delimiter);
+ );
+
+ if (!(buf = ast_str_thread_get(&result_buf, 16)) ||
+ !(previous_value = ast_str_thread_get(&tmp_buf, 16))) {
+ return -1;
+ }
+
+ AST_STANDARD_APP_ARGS(args, data);
+
+ if (ast_strlen_zero(args.var)) {
+ ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
+ return -1;
+ }
+
+ if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
+ ast_get_encoded_char(args.delimiter, delimiter, &unused);
+ }
+
+ varsubst = alloca(strlen(args.var) + 4);
+ sprintf(varsubst, "${%s}", args.var);
+ ast_str_substitute_variables(&previous_value, 0, chan, varsubst);
+
+ if (!ast_str_strlen(previous_value)) {
+ ast_str_set(&buf, 0, "%s", new_value);
+ } else {
+ ast_str_set(&buf, 0, "%s%c%s",
+ beginning ? new_value : ast_str_buffer(previous_value),
+ delimiter[0],
+ beginning ? ast_str_buffer(previous_value) : new_value);
+ }
+
+ pbx_builtin_setvar_helper(chan, args.var, ast_str_buffer(buf));
+
+ return 0;
+#undef beginning
+}
+
+static struct ast_custom_function push_function = {
+ .name = "PUSH",
+ .write = unshift_push,
+};
+
+static struct ast_custom_function unshift_function = {
+ .name = "UNSHIFT",
+ .write = unshift_push,
+};
+
+static int passthru(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+ snprintf(buf, len, "%s", data);
+ return 0;
+}
+
+static struct ast_custom_function passthru_function = {
+ .name = "PASSTHRU",
+ .read = passthru,
+};
+
static int unload_module(void)
{
int res = 0;
res |= ast_custom_function_unregister(&fieldqty_function);
res |= ast_custom_function_unregister(&filter_function);
+ res |= ast_custom_function_unregister(&replace_function);
res |= ast_custom_function_unregister(&listfilter_function);
res |= ast_custom_function_unregister(®ex_function);
res |= ast_custom_function_unregister(&array_function);
@@ -1018,6 +1317,11 @@
res |= ast_unregister_application(app_clearhash);
res |= ast_custom_function_unregister(&toupper_function);
res |= ast_custom_function_unregister(&tolower_function);
+ res |= ast_custom_function_unregister(&shift_function);
+ res |= ast_custom_function_unregister(&pop_function);
+ res |= ast_custom_function_unregister(&push_function);
+ res |= ast_custom_function_unregister(&unshift_function);
+ res |= ast_custom_function_unregister(&passthru_function);
return res;
}
@@ -1028,6 +1332,7 @@
res |= ast_custom_function_register(&fieldqty_function);
res |= ast_custom_function_register(&filter_function);
+ res |= ast_custom_function_register(&replace_function);
res |= ast_custom_function_register(&listfilter_function);
res |= ast_custom_function_register(®ex_function);
res |= ast_custom_function_register(&array_function);
@@ -1043,6 +1348,11 @@
res |= ast_register_application_xml(app_clearhash, exec_clearhash);
res |= ast_custom_function_register(&toupper_function);
res |= ast_custom_function_register(&tolower_function);
+ res |= ast_custom_function_register(&shift_function);
+ res |= ast_custom_function_register(&pop_function);
+ res |= ast_custom_function_register(&push_function);
+ res |= ast_custom_function_register(&unshift_function);
+ res |= ast_custom_function_register(&passthru_function);
return res;
}