Newer
Older
/* no insert after the last character */
if (c < (origsize - 1)) {
ast_str_append(buf, len, "%s", args.insert_string);
}
}
return 0;
}
static struct ast_custom_function strbetween_function = {
.name = "STRBETWEEN",
.read2 = strbetween,
};
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(null);
AST_APP_ARG(reg);
AST_APP_ARG(str);
int errcode;
regex_t regexbuf;
AST_NONSTANDARD_APP_ARGS(args, parse, '"');
Tilghman Lesher
committed
if (args.argc != 3) {
ast_log(LOG_ERROR, "Unexpected arguments: should have been in the form '\"<regex>\" <string>'\n");
return -1;
}
if ((*args.str == ' ') || (*args.str == '\t'))
args.str++;
Tilghman Lesher
committed
ast_debug(1, "FUNCTION REGEX (%s)(%s)\n", args.reg, args.str);
if ((errcode = regcomp(®exbuf, args.reg, REG_EXTENDED | REG_NOSUB))) {
regerror(errcode, ®exbuf, buf, len);
ast_log(LOG_WARNING, "Malformed input %s(%s): %s\n", cmd, parse, buf);
return -1;
Russell Bryant
committed
}
Russell Bryant
committed
strcpy(buf, regexec(®exbuf, args.str, 0, NULL, 0) ? "0" : "1");
Russell Bryant
committed
regfree(®exbuf);
static struct ast_custom_function regex_function = {
.read = regex,
#define HASH_PREFIX "~HASH~%s~"
#define HASH_FORMAT HASH_PREFIX "%s~"
static char *app_clearhash = "ClearHash";
/* This function probably should migrate to main/pbx.c, as pbx_builtin_clearvar_prefix() */
static void clearvar_prefix(struct ast_channel *chan, const char *prefix)
{
struct ast_var_t *var;
int len = strlen(prefix);
AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_varshead(chan), var, entries) {
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], "");
}
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
static const char *get_key(const struct ast_str *prefix, const struct ast_var_t *var)
{
const char *prefix_name = ast_str_buffer(prefix);
const char *var_name = ast_var_name(var);
int prefix_len;
int var_len;
if (ast_strlen_zero(var_name)) {
return NULL;
}
prefix_len = ast_str_strlen(prefix);
var_len = strlen(var_name);
/*
* Make sure we only match on non-empty, hash function created keys. If valid
* then return a pointer to the variable that's just after the prefix.
*/
return var_len > (prefix_len + 1) && var_name[var_len - 1] == '~' &&
strncmp(prefix_name, var_name, prefix_len) == 0 ? var_name + prefix_len : NULL;
}
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);
size_t buf_len;
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) {
const char *key = get_key(prefix, newvar);
if (key) {
strncat(buf, key, len - strlen(buf) - 1);
/* Replace the trailing ~ */
buf[strlen(buf) - 1] = ',';
}
}
/* Trim the trailing comma */
buf_len = strlen(buf);
if (buf_len) {
buf[buf_len - 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);
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) {
const char *key = get_key(prefix, newvar);
if (key) {
char *tmp;
ast_str_append(buf, len, "%s", key);
/* Replace the trailing ~ */
tmp = ast_str_buffer(*buf);
tmp[ast_str_strlen(*buf) - 1] = ',';
}
}
ast_str_truncate(*buf, -1);
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)
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
{
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);
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
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') {
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
*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,
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
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;
}
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
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
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
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 */
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
{"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);