Newer
Older
if (strncmp(prefix, ast_var_name(var), len) == 0) {
AST_LIST_REMOVE_CURRENT(entries);
Tilghman Lesher
committed
ast_free(var);
}
}
AST_LIST_TRAVERSE_SAFE_END
}
static int exec_clearhash(struct ast_channel *chan, const char *data)
{
char prefix[80];
snprintf(prefix, sizeof(prefix), HASH_PREFIX, data ? (char *)data : "null");
clearvar_prefix(chan, prefix);
return 0;
}
static int array(struct ast_channel *chan, const char *cmd, char *var,
AST_DECLARE_APP_ARGS(arg1,
);
AST_DECLARE_APP_ARGS(arg2,
char *origvar = "", *value2, varname[256];
int i, ishash = 0;
}
value2 = ast_strdupa(value);
if (!strcmp(cmd, "HASH")) {
const char *var2 = pbx_builtin_getvar_helper(chan, "~ODBCFIELDS~");
origvar = var;
if (var2)
var = ast_strdupa(var2);
else {
if (chan)
ast_autoservice_stop(chan);
return -1;
ishash = 1;
}
/* The functions this will generally be used with are SORT and ODBC_*, which
* both return comma-delimited lists. However, if somebody uses literal lists,
* their commas will be translated to vertical bars by the load, and I don't
* want them to be surprised by the result. Hence, we prefer commas as the
* delimiter, but we'll fall back to vertical bars if commas aren't found.
*/
ast_debug(1, "array (%s=%s)\n", var, S_OR(value2, ""));
Tilghman Lesher
committed
AST_STANDARD_APP_ARGS(arg1, var);
Tilghman Lesher
committed
AST_STANDARD_APP_ARGS(arg2, value2);
for (i = 0; i < arg1.argc; i++) {
ast_debug(1, "array set value (%s=%s)\n", arg1.var[i],
if (i < arg2.argc) {
if (ishash) {
if (origvar[0] == '_') {
if (origvar[1] == '_') {
snprintf(varname, sizeof(varname), "__" HASH_FORMAT, origvar + 2, arg1.var[i]);
} else {
snprintf(varname, sizeof(varname), "_" HASH_FORMAT, origvar + 1, arg1.var[i]);
}
} else {
snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
}
pbx_builtin_setvar_helper(chan, varname, arg2.val[i]);
} else {
pbx_builtin_setvar_helper(chan, arg1.var[i], arg2.val[i]);
}
} else {
/* We could unset the variable, by passing a NULL, but due to
* pushvar semantics, that could create some undesired behavior. */
if (ishash) {
snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
pbx_builtin_setvar_helper(chan, varname, "");
} else {
pbx_builtin_setvar_helper(chan, arg1.var[i], "");
}
static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
struct ast_var_t *newvar;
struct ast_str *prefix = ast_str_alloca(80);
if (!chan) {
ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
return -1;
}
ast_str_set(&prefix, -1, HASH_PREFIX, data);
memset(buf, 0, len);
AST_LIST_TRAVERSE(ast_channel_varshead(chan), newvar, entries) {
if (strncmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
/* Copy everything after the prefix */
strncat(buf, ast_var_name(newvar) + ast_str_strlen(prefix), len - strlen(buf) - 1);
/* Trim the trailing ~ */
buf[strlen(buf) - 1] = ',';
}
}
/* Trim the trailing comma */
buf[strlen(buf) - 1] = '\0';
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;
if (!chan) {
ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
return -1;
}
ast_str_set(&prefix, -1, HASH_PREFIX, data);
AST_LIST_TRAVERSE(ast_channel_varshead(chan), newvar, entries) {
if (strncmp(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];
AST_DECLARE_APP_ARGS(arg,
AST_APP_ARG(hashname);
AST_APP_ARG(hashkey);
);
Tilghman Lesher
committed
if (!strchr(var, ',')) {
/* Single argument version */
return array(chan, "HASH", var, value);
}
AST_STANDARD_APP_ARGS(arg, var);
if (arg.hashname[0] == '_') {
if (arg.hashname[1] == '_') {
snprintf(varname, sizeof(varname), "__" HASH_FORMAT, arg.hashname + 2, arg.hashkey);
} else {
snprintf(varname, sizeof(varname), "_" HASH_FORMAT, arg.hashname + 1, arg.hashkey);
}
} else {
snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
}
pbx_builtin_setvar_helper(chan, varname, value);
return 0;
}
static int hash_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
{
char varname[256];
const char *varvalue;
AST_DECLARE_APP_ARGS(arg,
AST_APP_ARG(hashname);
AST_APP_ARG(hashkey);
);
AST_STANDARD_APP_ARGS(arg, data);
if (arg.argc == 2) {
snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
varvalue = pbx_builtin_getvar_helper(chan, varname);
if (varvalue)
ast_copy_string(buf, varvalue, len);
else
*buf = '\0';
} else if (arg.argc == 1) {
char colnames[4096];
int i;
AST_DECLARE_APP_ARGS(arg2,
AST_APP_ARG(col)[100];
);
if (!chan) {
ast_log(LOG_WARNING, "No channel and only 1 parameter was provided to %s function.\n", cmd);
return -1;
}
/* Get column names, in no particular order */
hashkeys_read(chan, "HASHKEYS", arg.hashname, colnames, sizeof(colnames));
pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames);
Mark Michelson
committed
AST_STANDARD_APP_ARGS(arg2, colnames);
*buf = '\0';
/* Now get the corresponding column values, in exactly the same order */
for (i = 0; i < arg2.argc; i++) {
snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg2.col[i]);
varvalue = pbx_builtin_getvar_helper(chan, varname);
strncat(buf, varvalue, len - strlen(buf) - 1);
strncat(buf, ",", len - strlen(buf) - 1);
}
/* Strip trailing comma */
buf[strlen(buf) - 1] = '\0';
}
return 0;
}
static struct ast_custom_function hash_function = {
.name = "HASH",
.write = hash_write,
.read = hash_read,
};
static struct ast_custom_function hashkeys_function = {
.name = "HASHKEYS",
.read = hashkeys_read,
};
static struct ast_custom_function array_function = {
.write = array,
static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
char *bufptr = buf, *dataptr = data;
if (len < 3){ /* at least two for quotes and one for binary zero */
ast_log(LOG_ERROR, "Not enough buffer\n");
return -1;
}
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "No argument specified!\n");
ast_copy_string(buf, "\"\"", len);
return 0;
}
for (; bufptr < buf + len - 3; dataptr++) {
if (*dataptr == '\\') {
*bufptr++ = '\\';
*bufptr++ = '\\';
} else if (*dataptr == '"') {
*bufptr++ = '\\';
*bufptr++ = '"';
} else if (*dataptr == '\0') {
break;
} else {
*bufptr++ = *dataptr;
}
}
*bufptr++ = '"';
*bufptr = '\0';
}
static struct ast_custom_function quote_function = {
.name = "QUOTE",
static int csv_quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
char *bufptr = buf, *dataptr = data;
if (len < 3) { /* at least two for quotes and one for binary zero */
ast_log(LOG_ERROR, "Not enough buffer\n");
return -1;
}
if (ast_strlen_zero(data)) {
ast_copy_string(buf, "\"\"", len);
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
return 0;
}
*bufptr++ = '"';
for (; bufptr < buf + len - 3; dataptr++){
if (*dataptr == '"') {
*bufptr++ = '"';
*bufptr++ = '"';
} else if (*dataptr == '\0') {
break;
} else {
*bufptr++ = *dataptr;
}
}
*bufptr++ = '"';
*bufptr='\0';
return 0;
}
static struct ast_custom_function csv_quote_function = {
.name = "CSV_QUOTE",
.read = csv_quote,
};
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
{
int length = 0;
length = strlen(data);
snprintf(buf, buflen, "%d", length);
static struct ast_custom_function len_function = {
.read = len,
Kevin P. Fleming
committed
static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse,
char *buf, size_t buflen)
Kevin P. Fleming
committed
{
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(epoch);
AST_APP_ARG(timezone);
AST_APP_ARG(format);
struct timeval when;
Tilghman Lesher
committed
struct ast_tm tm;
Kevin P. Fleming
committed
buf[0] = '\0';
AST_STANDARD_APP_ARGS(args, parse);
ast_get_timeval(args.epoch, &when, ast_tvnow(), NULL);
ast_localtime(&when, &tm, args.timezone);
if (!args.format)
args.format = "%c";
if (ast_strftime(buf, buflen, args.format, &tm) <= 0)
ast_log(LOG_WARNING, "C function strftime() output nothing?!!\n");
buf[buflen - 1] = '\0';
Kevin P. Fleming
committed
}
static struct ast_custom_function strftime_function = {
Kevin P. Fleming
committed
.name = "STRFTIME",
.read = acf_strftime,
};
static int acf_strptime(struct ast_channel *chan, const char *cmd, char *data,
char *buf, size_t buflen)
AST_APP_ARG(timestring);
AST_APP_ARG(timezone);
AST_APP_ARG(format);
struct ast_tm tm;
buf[0] = '\0';
if (!data) {
ast_log(LOG_ERROR,
"Asterisk function STRPTIME() requires an argument.\n");
return -1;
}
AST_STANDARD_APP_ARGS(args, data);
if (ast_strlen_zero(args.format)) {
ast_log(LOG_ERROR,
Tilghman Lesher
committed
"No format supplied to STRPTIME(<timestring>,<timezone>,<format>)");
if (!ast_strptime(args.timestring, args.format, &tm)) {
ast_log(LOG_WARNING, "STRPTIME() found no time specified within the string\n");
struct timeval when;
when = ast_mktime(&tm, args.timezone);
snprintf(buf, buflen, "%d", (int) when.tv_sec);
static struct ast_custom_function strptime_function = {
.name = "STRPTIME",
.read = acf_strptime,
};
static int function_eval(struct ast_channel *chan, const char *cmd, char *data,
char *buf, size_t buflen)
ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
pbx_substitute_variables_helper(chan, data, buf, buflen - 1);
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,
static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
{
char *bufptr, *dataptr;
for (bufptr = buf, dataptr = data; bufptr < buf + buflen - 1; dataptr++) {
if (*dataptr == '\0') {
*bufptr++ = '\0';
break;
} else if (*dataptr == '1') {
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
*bufptr++ = '1';
} else if (strchr("AaBbCc2", *dataptr)) {
*bufptr++ = '2';
} else if (strchr("DdEeFf3", *dataptr)) {
*bufptr++ = '3';
} else if (strchr("GgHhIi4", *dataptr)) {
*bufptr++ = '4';
} else if (strchr("JjKkLl5", *dataptr)) {
*bufptr++ = '5';
} else if (strchr("MmNnOo6", *dataptr)) {
*bufptr++ = '6';
} else if (strchr("PpQqRrSs7", *dataptr)) {
*bufptr++ = '7';
} else if (strchr("TtUuVv8", *dataptr)) {
*bufptr++ = '8';
} else if (strchr("WwXxYyZz9", *dataptr)) {
*bufptr++ = '9';
} else if (*dataptr == '0') {
*bufptr++ = '0';
}
}
buf[buflen - 1] = '\0';
return 0;
}
static struct ast_custom_function keypadhash_function = {
.name = "KEYPADHASH",
.read = keypadhash,
};
static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
{
char *bufptr = buf, *dataptr = data;
while ((bufptr < buf + buflen - 1) && (*bufptr++ = toupper(*dataptr++)));
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,
};
static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
{
char *bufptr = buf, *dataptr = data;
while ((bufptr < buf + buflen - 1) && (*bufptr++ = tolower(*dataptr++)));
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,
};
Tilghman Lesher
committed
static int shift_pop(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Tilghman Lesher
committed
#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);
);
Tilghman Lesher
committed
if (!before) {
return -1;
}
Tilghman Lesher
committed
AST_STANDARD_APP_ARGS(args, data);
if (ast_strlen_zero(args.var)) {
Tilghman Lesher
committed
ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
return -1;
}
varsubst = ast_alloca(strlen(args.var) + 4);
Tilghman Lesher
committed
sprintf(varsubst, "${%s}", args.var);
ast_str_substitute_variables(&before, 0, chan, varsubst);
Tilghman Lesher
committed
if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
ast_get_encoded_char(args.delimiter, delimiter, &unused);
Tilghman Lesher
committed
if (!ast_str_strlen(before)) {
/* Nothing to pop */
return -1;
}
Tilghman Lesher
committed
if (!(after = search_func(ast_str_buffer(before), delimiter[0]))) {
/* Only one entry in array */
ast_str_set(buf, len, "%s", ast_str_buffer(before));
pbx_builtin_setvar_helper(chan, args.var, "");
} else {
*after++ = '\0';
Tilghman Lesher
committed
ast_str_set(buf, len, "%s", beginning ? ast_str_buffer(before) : after);
pbx_builtin_setvar_helper(chan, args.var, beginning ? after : ast_str_buffer(before));
}
return 0;
Tilghman Lesher
committed
#undef beginning
}
static struct ast_custom_function shift_function = {
.name = "SHIFT",
Tilghman Lesher
committed
.read2 = shift_pop,
};
static struct ast_custom_function pop_function = {
.name = "POP",
Tilghman Lesher
committed
.read2 = shift_pop,
Tilghman Lesher
committed
static int unshift_push(struct ast_channel *chan, const char *cmd, char *data, const char *new_value)
Tilghman Lesher
committed
#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);
);
const char *stripped_var;
Tilghman Lesher
committed
if (!(buf = ast_str_thread_get(&result_buf, 16)) ||
!(previous_value = ast_str_thread_get(&tmp_buf, 16))) {
return -1;
}
Tilghman Lesher
committed
AST_STANDARD_APP_ARGS(args, data);
Tilghman Lesher
committed
if (ast_strlen_zero(args.var)) {
ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
return -1;
}
Tilghman Lesher
committed
if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
ast_get_encoded_char(args.delimiter, delimiter, &unused);
/* UNSHIFT and PUSH act as ways of setting a variable, so we need to be
* sure to skip leading underscores if they appear. However, we only want
* to skip up to two since that is the maximum number that can be used to
* indicate variable inheritance. Any further underscores are part of the
* variable name.
*/
stripped_var = args.var + MIN(strspn(args.var, "_"), 2);
varsubst = ast_alloca(strlen(stripped_var) + 4);
sprintf(varsubst, "${%s}", stripped_var);
Tilghman Lesher
committed
ast_str_substitute_variables(&previous_value, 0, chan, varsubst);
Tilghman Lesher
committed
if (!ast_str_strlen(previous_value)) {
ast_str_set(&buf, 0, "%s", new_value);
Tilghman Lesher
committed
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;
Tilghman Lesher
committed
#undef beginning
}
static struct ast_custom_function push_function = {
.name = "PUSH",
Tilghman Lesher
committed
.write = unshift_push,
Tilghman Lesher
committed
static struct ast_custom_function unshift_function = {
.name = "UNSHIFT",
.write = unshift_push,
};
static int passthru(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Tilghman Lesher
committed
ast_str_set(buf, len, "%s", data);
return 0;
Tilghman Lesher
committed
static struct ast_custom_function passthru_function = {
.name = "PASSTHRU",
.read2 = passthru,
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
AST_TEST_DEFINE(test_FIELDNUM)
{
int i, res = AST_TEST_PASS;
struct ast_channel *chan;
struct ast_str *str;
char expression[256];
struct {
const char *fields;
const char *delim;
const char *field;
const char *expected;
} test_args[] = {
{"abc,def,ghi,jkl", "\\,", "ghi", "3"},
{"abc def ghi jkl", " ", "abc", "1"},
{"abc/def/ghi/jkl", "\\\\x2f", "def", "2"},
{"abc$def$ghi$jkl", "", "ghi", "0"},
{"abc,def,ghi,jkl", "-", "", "0"},
{"abc-def-ghi-jkl", "-", "mno", "0"}
};
switch (cmd) {
case TEST_INIT:
info->name = "func_FIELDNUM_test";
info->category = "/funcs/func_strings/";
info->summary = "Test FIELDNUM function";
info->description = "Verify FIELDNUM behavior";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
if (!(chan = ast_dummy_channel_alloc())) {
ast_test_status_update(test, "Unable to allocate dummy channel\n");
return AST_TEST_FAIL;
}
if (!(str = ast_str_create(16))) {
ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
ast_channel_release(chan);
return AST_TEST_FAIL;
}
for (i = 0; i < ARRAY_LEN(test_args); i++) {
struct ast_var_t *var = ast_var_assign("FIELDS", test_args[i].fields);
if (!var) {
ast_test_status_update(test, "Out of memory\n");
res = AST_TEST_FAIL;
break;
}
AST_LIST_INSERT_HEAD(ast_channel_varshead(chan), var, entries);
snprintf(expression, sizeof(expression), "${FIELDNUM(%s,%s,%s)}", var->name, test_args[i].delim, test_args[i].field);
ast_str_substitute_variables(&str, 0, chan, expression);
AST_LIST_REMOVE(ast_channel_varshead(chan), var, entries);
ast_var_delete(var);
if (strcasecmp(ast_str_buffer(str), test_args[i].expected)) {
ast_test_status_update(test, "Evaluation of '%s' returned '%s' instead of the expected value '%s'\n",
expression, ast_str_buffer(str), test_args[i].expected);
res = AST_TEST_FAIL;
break;
}
}
ast_free(str);
ast_channel_release(chan);
return res;
}
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
AST_TEST_DEFINE(test_REPLACE)
{
int i, res = AST_TEST_PASS;
struct ast_channel *chan;
struct ast_str *str;
char expression[256];
struct {
const char *test_string;
const char *find_chars;
const char *replace_char;
const char *expected;
} test_args[] = {
{"abc,def", "\\,", "-", "abc-def"},
{"abc,abc", "bc", "a", "aaa,aaa"},
{"abc,def", "x", "?", "abc,def"},
{"abc,def", "\\,", "", "abcdef"}
};
switch (cmd) {
case TEST_INIT:
info->name = "func_REPLACE_test";
info->category = "/funcs/func_strings/";
info->summary = "Test REPLACE function";
info->description = "Verify REPLACE behavior";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
if (!(chan = ast_dummy_channel_alloc())) {
ast_test_status_update(test, "Unable to allocate dummy channel\n");
return AST_TEST_FAIL;
}
if (!(str = ast_str_create(16))) {
ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
ast_channel_release(chan);
return AST_TEST_FAIL;
}
for (i = 0; i < ARRAY_LEN(test_args); i++) {
struct ast_var_t *var = ast_var_assign("TEST_STRING", test_args[i].test_string);
if (!var) {
ast_test_status_update(test, "Out of memory\n");
res = AST_TEST_FAIL;
break;
}
AST_LIST_INSERT_HEAD(ast_channel_varshead(chan), var, entries);
snprintf(expression, sizeof(expression), "${REPLACE(%s,%s,%s)}", var->name, test_args[i].find_chars, test_args[i].replace_char);
ast_str_substitute_variables(&str, 0, chan, expression);
AST_LIST_REMOVE(ast_channel_varshead(chan), var, entries);
ast_var_delete(var);
if (strcasecmp(ast_str_buffer(str), test_args[i].expected)) {
ast_test_status_update(test, "Evaluation of '%s' returned '%s' instead of the expected value '%s'\n",
expression, ast_str_buffer(str), test_args[i].expected);
res = AST_TEST_FAIL;
break;
}
}
ast_free(str);
ast_channel_release(chan);
return res;
}
AST_TEST_DEFINE(test_FILTER)
{
int i, res = AST_TEST_PASS;
const char *test_strings[][2] = {
{"A-R", "DAHDI"},
{"A\\-R", "A"},
{"\\x41-R", "DAHDI"},
{"0-9A-Ca-c", "0042133333A12212"},
{"0-9a-cA-C_+\\-", "0042133333A12212"},
{NULL, NULL},
};
switch (cmd) {
case TEST_INIT:
info->name = "func_FILTER_test";
Tilghman Lesher
committed
info->category = "/funcs/func_strings/";
info->summary = "Test FILTER function";
info->description = "Verify FILTER behavior";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
for (i = 0; test_strings[i][0]; i++) {
char tmp[256], tmp2[256] = "";
snprintf(tmp, sizeof(tmp), "${FILTER(%s,0042133333&DAHDI/g1/2212)}", test_strings[i][0]);
pbx_substitute_variables_helper(NULL, tmp, tmp2, sizeof(tmp2) - 1);
if (strcmp(test_strings[i][1], tmp2)) {
ast_test_status_update(test, "Format string '%s' substituted to '%s'. Expected '%s'.\n", test_strings[i][0], tmp2, test_strings[i][1]);
res = AST_TEST_FAIL;
}
}
return res;
}
AST_TEST_DEFINE(test_STRREPLACE)
{
int i, res = AST_TEST_PASS;
struct ast_channel *chan; /* dummy channel */
struct ast_str *str; /* fancy string for holding comparing value */
const char *test_strings[][5] = {
{"Weasels have eaten my telephone system", "have eaten my", "are eating our", "", "Weasels are eating our telephone system"}, /*Test normal conditions */
{"Did you know twenty plus two is twenty-two?", "twenty", "thirty", NULL, "Did you know thirty plus two is thirty-two?"}, /* Test no third comma */
{"foofoofoofoofoofoofoo", "foofoo", "bar", NULL, "barbarbarfoo"}, /* Found string within previous match */
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
{"My pet dog once ate a dog who sat on a dog while eating a corndog.", "dog", "cat", "3", "My pet cat once ate a cat who sat on a cat while eating a corndog."},
{"One and one and one is three", "and", "plus", "1", "One plus one and one is three"}, /* Test <max-replacements> = 1*/
{"", "fhqwagads", "spelunker", NULL, ""}, /* Empty primary string */
{"Part of this string is missing.", "missing", NULL, NULL, "Part of this string is ."}, /* Empty replace string */
{"'Accidentally' left off a bunch of stuff.", NULL, NULL, NULL, ""}, /* Deliberate error test from too few args */
{"This test will also error.", "", "", "", ""}, /* Deliberate error test from blank find string */
{"This is an \"escape character\" test.", "\\\"escape character\\\"", "evil", NULL, "This is an evil test."}
};
switch (cmd) {
case TEST_INIT:
info->name = "func_STRREPLACE_test";
info->category = "/funcs/func_strings/";
info->summary = "Test STRREPLACE function";
info->description = "Verify STRREPLACE behavior";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
if (!(chan = ast_dummy_channel_alloc())) {
ast_test_status_update(test, "Unable to allocate dummy channel\n");
return AST_TEST_FAIL;
}
if (!(str = ast_str_create(64))) {
ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
ast_channel_release(chan);
return AST_TEST_FAIL;
}
for (i = 0; i < ARRAY_LEN(test_strings); i++) {
char tmp[512], tmp2[512] = "";
struct ast_var_t *var = ast_var_assign("test_string", test_strings[i][0]);
if (!var) {
ast_test_status_update(test, "Unable to allocate variable\n");
ast_free(str);
ast_channel_release(chan);
return AST_TEST_FAIL;
}
AST_LIST_INSERT_HEAD(ast_channel_varshead(chan), var, entries);
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
if (test_strings[i][3]) {
snprintf(tmp, sizeof(tmp), "${STRREPLACE(%s,%s,%s,%s)}", "test_string", test_strings[i][1], test_strings[i][2], test_strings[i][3]);
} else if (test_strings[i][2]) {
snprintf(tmp, sizeof(tmp), "${STRREPLACE(%s,%s,%s)}", "test_string", test_strings[i][1], test_strings[i][2]);
} else if (test_strings[i][1]) {
snprintf(tmp, sizeof(tmp), "${STRREPLACE(%s,%s)}", "test_string", test_strings[i][1]);
} else {
snprintf(tmp, sizeof(tmp), "${STRREPLACE(%s)}", "test_string");
}
ast_str_substitute_variables(&str, 0, chan, tmp);
if (strcmp(test_strings[i][4], ast_str_buffer(str))) {
ast_test_status_update(test, "Format string '%s' substituted to '%s'. Expected '%s'.\n", test_strings[i][0], tmp2, test_strings[i][4]);
res = AST_TEST_FAIL;
}
}
ast_free(str);
ast_channel_release(chan);
return res;
}
static int unload_module(void)
{
int res = 0;
AST_TEST_UNREGISTER(test_FIELDNUM);
AST_TEST_UNREGISTER(test_REPLACE);
AST_TEST_UNREGISTER(test_FILTER);
res |= ast_custom_function_unregister(&fieldqty_function);
res |= ast_custom_function_unregister(&fieldnum_function);
res |= ast_custom_function_unregister(&filter_function);
Tilghman Lesher
committed
res |= ast_custom_function_unregister(&replace_function);
res |= ast_custom_function_unregister(&strreplace_function);
Tilghman Lesher
committed
res |= ast_custom_function_unregister(&listfilter_function);
res |= ast_custom_function_unregister(®ex_function);
res |= ast_custom_function_unregister(&array_function);
res |= ast_custom_function_unregister("e_function);
res |= ast_custom_function_unregister(&csv_quote_function);
res |= ast_custom_function_unregister(&len_function);
res |= ast_custom_function_unregister(&strftime_function);
res |= ast_custom_function_unregister(&strptime_function);
res |= ast_custom_function_unregister(&eval_function);
res |= ast_custom_function_unregister(&keypadhash_function);
res |= ast_custom_function_unregister(&hashkeys_function);
res |= ast_custom_function_unregister(&hash_function);
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);
Tilghman Lesher
committed
res |= ast_custom_function_unregister(&passthru_function);
return res;
}
static int load_module(void)
{
int res = 0;
AST_TEST_REGISTER(test_FIELDNUM);
AST_TEST_REGISTER(test_REPLACE);
AST_TEST_REGISTER(test_FILTER);
res |= ast_custom_function_register(&fieldqty_function);
res |= ast_custom_function_register(&fieldnum_function);
res |= ast_custom_function_register(&filter_function);
Tilghman Lesher
committed
res |= ast_custom_function_register(&replace_function);
res |= ast_custom_function_register(&strreplace_function);
Tilghman Lesher
committed
res |= ast_custom_function_register(&listfilter_function);
res |= ast_custom_function_register(®ex_function);
res |= ast_custom_function_register(&array_function);
res |= ast_custom_function_register("e_function);
res |= ast_custom_function_register(&csv_quote_function);
res |= ast_custom_function_register(&len_function);
res |= ast_custom_function_register(&strftime_function);
res |= ast_custom_function_register(&strptime_function);
res |= ast_custom_function_register(&eval_function);
res |= ast_custom_function_register(&keypadhash_function);
res |= ast_custom_function_register(&hashkeys_function);
res |= ast_custom_function_register(&hash_function);
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);
Tilghman Lesher
committed
res |= ast_custom_function_register(&passthru_function);