538 static int function_fieldqty_helper(
struct ast_channel *chan,
const char *cmd,
539 char *parse,
char *buf,
struct ast_str **sbuf, ssize_t len)
559 varsubst =
ast_alloca(strlen(args.varname) + 4);
561 sprintf(varsubst,
"${%s}", args.varname);
567 while (strsep(&varval, delim)) {
577 snprintf(buf, len,
"%d", fieldcount);
583 static int function_fieldqty(
struct ast_channel *chan,
const char *cmd,
584 char *parse,
char *buf,
size_t len)
586 return function_fieldqty_helper(chan, cmd, parse, buf, NULL, len);
589 static int function_fieldqty_str(
struct ast_channel *chan,
const char *cmd,
590 char *parse,
struct ast_str **buf, ssize_t len)
592 return function_fieldqty_helper(chan, cmd, parse, NULL, buf, len);
597 .read = function_fieldqty,
598 .read2 = function_fieldqty_str,
601 static int function_fieldnum_helper(
struct ast_channel *chan,
const char *cmd,
602 char *parse,
char *buf,
struct ast_str **sbuf, ssize_t len)
604 char *varsubst, *field;
606 int fieldindex = 0, res = 0;
622 ast_log(LOG_ERROR,
"Usage: FIELDNUM(<listname>,<delimiter>,<fieldvalue>)\n");
625 varsubst =
ast_alloca(strlen(args.varname) + 4);
626 sprintf(varsubst,
"${%s}", args.varname);
637 while ((field = strsep(&varval, delim)) != NULL) {
640 if (!strcasecmp(field, args.field)) {
656 snprintf(buf, len,
"%d", fieldindex);
662 static int function_fieldnum(
struct ast_channel *chan,
const char *cmd,
663 char *parse,
char *buf,
size_t len)
665 return function_fieldnum_helper(chan, cmd, parse, buf, NULL, len);
668 static int function_fieldnum_str(
struct ast_channel *chan,
const char *cmd,
669 char *parse,
struct ast_str **buf, ssize_t len)
671 return function_fieldnum_helper(chan, cmd, parse, NULL, buf, len);
676 .read = function_fieldnum,
677 .read2 = function_fieldnum_str,
680 static int listfilter(
struct ast_channel *chan,
const char *cmd,
char *parse,
char *buf,
struct ast_str **bufstr, ssize_t len)
688 const char *begin, *cur, *next;
689 int dlen, flen, first = 1;
690 struct ast_str *result, **result_ptr = &result;
691 char *delim, *varsubst;
705 ast_log(LOG_ERROR,
"Usage: LISTFILTER(<listname>,<delimiter>,<fieldvalue>)\n");
709 varsubst =
ast_alloca(strlen(args.listname) + 4);
710 sprintf(varsubst,
"${%s}", args.listname);
714 ast_channel_lock(chan);
719 ast_channel_unlock(chan);
732 ast_channel_unlock(chan);
737 dlen = strlen(args.delimiter);
741 if ((dlen = strlen(delim)) == 0) {
746 flen = strlen(args.fieldvalue);
751 ast_str_make_space(result_ptr, len ? len :
ast_str_strlen(orig_list) + 1);
755 next = strstr(begin, delim);
761 next = strstr(cur + dlen, delim);
763 cur = strchr(begin + dlen,
'\0');
766 if (flen == cur - begin && !strncmp(begin, args.fieldvalue, flen)) {
768 begin += flen + dlen;
779 }
while (*cur !=
'\0');
781 ast_channel_unlock(chan);
791 static int listfilter_read(
struct ast_channel *chan,
const char *cmd,
char *parse,
char *buf,
size_t len)
793 return listfilter(chan, cmd, parse, buf, NULL, len);
796 static int listfilter_read2(
struct ast_channel *chan,
const char *cmd,
char *parse,
struct ast_str **buf, ssize_t len)
798 return listfilter(chan, cmd, parse, NULL, buf, len);
802 .
name =
"LISTFILTER",
803 .read = listfilter_read,
804 .read2 = listfilter_read2,
816 char allowed[256] =
"";
817 size_t allowedlen = 0;
818 int32_t bitfield[8] = { 0, };
820 AST_STANDARD_RAW_ARGS(args, parse);
823 ast_log(LOG_ERROR,
"Usage: FILTER(<allowed-chars>,<string>)\n");
827 if (args.allowed[0] ==
'"' && !ast_opt_dont_warn) {
828 ast_log(LOG_WARNING,
"FILTER allowed characters includes the quote (\") character. This may not be what you want.\n");
832 for (; *(args.allowed);) {
838 args.allowed += consumed;
840 if (*(args.allowed) ==
'-') {
843 args.allowed += consumed + 1;
845 if ((
unsigned char) c2 < (
unsigned char) c1 && !ast_opt_dont_warn) {
846 ast_log(LOG_WARNING,
"Range wrapping in FILTER(%s,%s). This may not be what you want.\n", parse, args.string);
853 for (ac = (
unsigned char) c1; ac != (
unsigned char) c2; ac++) {
854 bitfield[ac / 32] |= 1 << (ac % 32);
856 bitfield[ac / 32] |= 1 << (ac % 32);
860 ac = (
unsigned char) c1;
861 ast_debug(4,
"c1=%d, consumed=%d, args.allowed=%s\n", c1, (
int) consumed, args.allowed - consumed);
862 bitfield[ac / 32] |= 1 << (ac % 32);
866 for (ac = 1; ac != 0; ac++) {
867 if (bitfield[ac / 32] & (1 << (ac % 32))) {
868 allowed[allowedlen++] = ac;
874 for (; *(args.string) && (buf + len - 1 > outbuf); (args.string)++) {
875 if (strchr(allowed, *(args.string)))
876 *outbuf++ = *(args.string);
888 static int replace(
struct ast_channel *chan,
const char *cmd,
char *data,
struct ast_str **buf, ssize_t len)
895 char *strptr, *varsubst;
898 char replace[2] =
"";
908 ast_log(LOG_ERROR,
"Usage: %s(<varname>,<search-chars>[,<replace-char>])\n", cmd);
916 if (ast_strlen_zero(find) || ast_strlen_zero(args.varname)) {
917 ast_log(LOG_ERROR,
"The characters to search for and the variable name must not be empty.\n");
921 varsubst =
ast_alloca(strlen(args.varname) + 4);
922 sprintf(varsubst,
"${%s}", args.varname);
931 ast_debug(3,
"Characters to find: (%s)\n", find);
932 ast_debug(3,
"Character to replace with: (%s)\n", replace);
937 if (strchr(find, *strptr)) {
938 if (ast_strlen_zero(replace)) {
939 memmove(strptr, strptr + 1, strlen(strptr + 1) + 1);
957 static int strreplace(
struct ast_channel *chan,
const char *cmd,
char *data,
struct ast_str **buf, ssize_t len)
963 unsigned max_matches;
989 "Usage: %s(<varname>,<find-string>[,<replace-string>,[<max-replacements>]])\n",
995 if (ast_strlen_zero(args.varname)) {
1000 if (ast_strlen_zero(args.find_string)) {
1001 ast_log(LOG_ERROR,
"No <find-string> specified\n");
1004 find_size = strlen(args.find_string);
1007 varsubstr =
ast_alloca(strlen(args.varname) + 4);
1008 sprintf(varsubstr,
"${%s}", args.varname);
1012 if (!args.max_replacements
1013 || (max_matches = atoi(args.max_replacements)) <= 0) {
1020 for (count = 0; count < max_matches; ++count) {
1021 end = strstr(start, args.find_string);
1030 if (args.replace_string) {
1034 start = end + find_size;
1042 .
name =
"STRREPLACE",
1043 .read2 = strreplace,
1046 static int strbetween(
struct ast_channel *chan,
const char *cmd,
char *data,
struct ast_str **buf, ssize_t len)
1049 char *varsubstr, *origstr;
1061 ast_log(LOG_ERROR,
"Couldn't obtain string\n");
1067 if (args.argc != 2 || ast_strlen_zero(args.varname)) {
1068 ast_log(LOG_ERROR,
"Usage: %s(<varname>,<insert-string>)\n", cmd);
1072 varsubstr =
ast_alloca(strlen(args.varname) + 4);
1073 sprintf(varsubstr,
"${%s}", args.varname);
1076 origsize = strlen(origstr);
1077 for (c = 0; c < origsize; c++) {
1080 if (c < (origsize - 1)) {
1089 .
name =
"STRBETWEEN",
1090 .read2 = strbetween,
1093 #define ltrim(s) while (isspace(*s)) s++;
1094 #define rtrim(s) { \
1096 char *back = s + strlen(s); \
1097 while (back != s && isspace(*--back)); \
1099 *(back + 1) = '\0'; \
1104 static int function_trim(
struct ast_channel *chan,
const char *cmd,
char *data,
char *buf,
size_t len)
1108 if (ast_strlen_zero(data)) {
1121 static int function_ltrim(
struct ast_channel *chan,
const char *cmd,
char *data,
char *buf,
size_t len)
1125 if (ast_strlen_zero(data)) {
1137 static int function_rtrim(
struct ast_channel *chan,
const char *cmd,
char *data,
char *buf,
size_t len)
1141 if (ast_strlen_zero(data)) {
1158 .read = function_trim,
1163 .read = function_ltrim,
1168 .read = function_rtrim,
1171 static int regex(
struct ast_channel *chan,
const char *cmd,
char *parse,
char *buf,
1186 if (args.argc != 3) {
1187 ast_log(LOG_ERROR,
"Unexpected arguments: should have been in the form '\"<regex>\" <string>'\n");
1190 if ((*args.str ==
' ') || (*args.str ==
'\t'))
1193 ast_debug(1,
"FUNCTION REGEX (%s)(%s)\n", args.reg, args.str);
1195 if ((errcode = regcomp(®exbuf, args.reg, REG_EXTENDED | REG_NOSUB))) {
1196 regerror(errcode, ®exbuf, buf, len);
1197 ast_log(LOG_WARNING,
"Malformed input %s(%s): %s\n", cmd, parse, buf);
1201 strcpy(buf, regexec(®exbuf, args.str, 0, NULL, 0) ?
"0" :
"1");
1213 #define HASH_PREFIX "~HASH~%s~"
1214 #define HASH_FORMAT HASH_PREFIX "%s~"
1216 static char *app_clearhash =
"ClearHash";
1219 static void clearvar_prefix(
struct ast_channel *chan,
const char *prefix)
1222 int len = strlen(prefix);
1224 if (strncmp(prefix, ast_var_name(var), len) == 0) {
1232 static int exec_clearhash(
struct ast_channel *chan,
const char *data)
1235 snprintf(prefix,
sizeof(prefix), HASH_PREFIX, data ? (
char *)data :
"null");
1236 clearvar_prefix(chan, prefix);
1240 static int array(
struct ast_channel *chan,
const char *cmd,
char *var,
1249 char *origvar =
"", *value2, varname[256];
1257 if (!strcmp(cmd,
"HASH")) {
1281 for (i = 0; i < arg1.argc; i++) {
1282 ast_debug(1,
"array set value (%s=%s)\n", arg1.var[i],
1283 S_OR(arg2.val[i],
""));
1284 if (i < arg2.argc) {
1286 if (origvar[0] ==
'_') {
1287 if (origvar[1] ==
'_') {
1288 snprintf(varname,
sizeof(varname),
"__" HASH_FORMAT, origvar + 2, arg1.var[i]);
1290 snprintf(varname,
sizeof(varname),
"_" HASH_FORMAT, origvar + 1, arg1.var[i]);
1293 snprintf(varname,
sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
1304 snprintf(varname,
sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
1315 static const char *get_key(
const struct ast_str *prefix,
const struct ast_var_t *var)
1318 const char *var_name = ast_var_name(var);
1322 if (ast_strlen_zero(var_name)) {
1327 var_len = strlen(var_name);
1333 return var_len > (prefix_len + 1) && var_name[var_len - 1] ==
'~' &&
1334 strncmp(prefix_name, var_name, prefix_len) == 0 ? var_name + prefix_len : NULL;
1337 static int hashkeys_read(
struct ast_channel *chan,
const char *cmd,
char *data,
char *buf,
size_t len)
1340 struct ast_str *prefix = ast_str_alloca(80);
1344 ast_log(LOG_WARNING,
"No channel was provided to %s function.\n", cmd);
1349 memset(buf, 0, len);
1352 const char *key = get_key(prefix, newvar);
1355 strncat(buf, key, len - strlen(buf) - 1);
1357 buf[strlen(buf) - 1] =
',';
1361 buf_len = strlen(buf);
1363 buf[buf_len - 1] =
'\0';
1368 static int hashkeys_read2(
struct ast_channel *chan,
const char *cmd,
char *data,
struct ast_str **buf, ssize_t len)
1371 struct ast_str *prefix = ast_str_alloca(80);
1374 ast_log(LOG_WARNING,
"No channel was provided to %s function.\n", cmd);
1381 const char *key = get_key(prefix, newvar);
1397 static int hash_write(
struct ast_channel *chan,
const char *cmd,
char *var,
const char *value)
1405 if (!strchr(var,
',')) {
1407 return array(chan,
"HASH", var, value);
1411 if (arg.hashname[0] ==
'_') {
1412 if (arg.hashname[1] ==
'_') {
1413 snprintf(varname,
sizeof(varname),
"__" HASH_FORMAT, arg.hashname + 2, arg.hashkey);
1415 snprintf(varname,
sizeof(varname),
"_" HASH_FORMAT, arg.hashname + 1, arg.hashkey);
1418 snprintf(varname,
sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
1425 static int hash_read(
struct ast_channel *chan,
const char *cmd,
char *data,
char *buf,
size_t len)
1428 const char *varvalue;
1435 if (arg.argc == 2) {
1436 snprintf(varname,
sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
1442 }
else if (arg.argc == 1) {
1443 char colnames[4096];
1450 ast_log(LOG_WARNING,
"No channel and only 1 parameter was provided to %s function.\n", cmd);
1455 hashkeys_read(chan,
"HASHKEYS", arg.hashname, colnames,
sizeof(colnames));
1462 for (i = 0; i < arg2.argc; i++) {
1463 snprintf(varname,
sizeof(varname), HASH_FORMAT, arg.hashname, arg2.col[i]);
1465 strncat(buf, varvalue, len - strlen(buf) - 1);
1466 strncat(buf,
",", len - strlen(buf) - 1);
1470 buf[strlen(buf) - 1] =
'\0';
1478 .write = hash_write,
1484 .read = hashkeys_read,
1485 .read2 = hashkeys_read2,
1493 static int quote(
struct ast_channel *chan,
const char *cmd,
char *data,
char *buf,
size_t len)
1495 char *bufptr = buf, *dataptr = data;
1498 ast_log(LOG_ERROR,
"Not enough buffer\n");
1502 if (ast_strlen_zero(data)) {
1503 ast_log(LOG_WARNING,
"No argument specified!\n");
1509 for (; bufptr < buf + len - 3; dataptr++) {
1510 if (*dataptr ==
'\\') {
1513 }
else if (*dataptr ==
'"') {
1516 }
else if (*dataptr ==
'\0') {
1519 *bufptr++ = *dataptr;
1532 static int csv_quote(
struct ast_channel *chan,
const char *cmd,
char *data,
char *buf,
size_t len)
1534 char *bufptr = buf, *dataptr = data;
1537 ast_log(LOG_ERROR,
"Not enough buffer\n");
1541 if (ast_strlen_zero(data)) {
1547 for (; bufptr < buf + len - 3; dataptr++){
1548 if (*dataptr ==
'"') {
1551 }
else if (*dataptr ==
'\0') {
1554 *bufptr++ = *dataptr;
1563 .
name =
"CSV_QUOTE",
1567 static int len(
struct ast_channel *chan,
const char *cmd,
char *data,
char *buf,
size_t buflen)
1572 length = strlen(data);
1574 snprintf(buf, buflen,
"%d", length);
1585 static int acf_strftime(
struct ast_channel *chan,
const char *cmd,
char *parse,
1586 char *buf,
size_t buflen)
1593 struct timeval when;
1607 ast_log(LOG_WARNING,
"C function strftime() output nothing?!!\n");
1609 buf[buflen - 1] =
'\0';
1616 .read = acf_strftime,
1619 static int acf_strptime(
struct ast_channel *chan,
const char *cmd,
char *data,
1620 char *buf,
size_t buflen)
1633 "Asterisk function STRPTIME() requires an argument.\n");
1639 if (ast_strlen_zero(args.format)) {
1641 "No format supplied to STRPTIME(<timestring>,<timezone>,<format>)");
1645 if (!
ast_strptime(args.timestring, args.format, &tm)) {
1646 ast_log(LOG_WARNING,
"STRPTIME() found no time specified within the string\n");
1648 struct timeval when;
1650 snprintf(buf, buflen,
"%d", (
int) when.tv_sec);
1658 .read = acf_strptime,
1661 static int function_eval(
struct ast_channel *chan,
const char *cmd,
char *data,
1662 char *buf,
size_t buflen)
1664 if (ast_strlen_zero(data)) {
1665 ast_log(LOG_WARNING,
"EVAL requires an argument: EVAL(<string>)\n");
1669 pbx_substitute_variables_helper(chan, data, buf, buflen - 1);
1674 static int function_eval2(
struct ast_channel *chan,
const char *cmd,
char *data,
1675 struct ast_str **buf, ssize_t buflen)
1677 if (ast_strlen_zero(data)) {
1678 ast_log(LOG_WARNING,
"EVAL requires an argument: EVAL(<string>)\n");
1689 .read = function_eval,
1690 .read2 = function_eval2,
1693 static int keypadhash(
struct ast_channel *chan,
const char *cmd,
char *data,
char *buf,
size_t buflen)
1695 char *bufptr, *dataptr;
1697 for (bufptr = buf, dataptr = data; bufptr < buf + buflen - 1; dataptr++) {
1698 if (*dataptr ==
'\0') {
1701 }
else if (*dataptr ==
'1') {
1703 }
else if (strchr(
"AaBbCc2", *dataptr)) {
1705 }
else if (strchr(
"DdEeFf3", *dataptr)) {
1707 }
else if (strchr(
"GgHhIi4", *dataptr)) {
1709 }
else if (strchr(
"JjKkLl5", *dataptr)) {
1711 }
else if (strchr(
"MmNnOo6", *dataptr)) {
1713 }
else if (strchr(
"PpQqRrSs7", *dataptr)) {
1715 }
else if (strchr(
"TtUuVv8", *dataptr)) {
1717 }
else if (strchr(
"WwXxYyZz9", *dataptr)) {
1719 }
else if (*dataptr ==
'0') {
1723 buf[buflen - 1] =
'\0';
1729 .
name =
"KEYPADHASH",
1733 static int string_toupper(
struct ast_channel *chan,
const char *cmd,
char *data,
char *buf,
size_t buflen)
1735 char *bufptr = buf, *dataptr = data;
1737 while ((bufptr < buf + buflen - 1) && (*bufptr++ = toupper(*dataptr++)));
1742 static int string_toupper2(
struct ast_channel *chan,
const char *cmd,
char *data,
struct ast_str **buf, ssize_t buflen)
1744 char *bufptr, *dataptr = data;
1747 ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
1758 .read = string_toupper,
1759 .read2 = string_toupper2,
1762 static int string_tolower(
struct ast_channel *chan,
const char *cmd,
char *data,
char *buf,
size_t buflen)
1764 char *bufptr = buf, *dataptr = data;
1766 while ((bufptr < buf + buflen - 1) && (*bufptr++ = tolower(*dataptr++)));
1771 static int string_tolower2(
struct ast_channel *chan,
const char *cmd,
char *data,
struct ast_str **buf, ssize_t buflen)
1773 char *bufptr, *dataptr = data;
1776 ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
1787 .read = string_tolower,
1788 .read2 = string_tolower2,
1791 static int shift_pop(
struct ast_channel *chan,
const char *cmd,
char *data,
struct ast_str **buf, ssize_t len)
1793 #define beginning (cmd[0] == 'S')
1794 char *after, delimiter[2] =
",", *varsubst;
1797 char *(*search_func)(
const char *s,
int c) = (beginning ? strchr : strrchr);
1809 if (ast_strlen_zero(args.var)) {
1810 ast_log(LOG_WARNING,
"%s requires a variable name\n", cmd);
1815 sprintf(varsubst,
"${%s}", args.var);
1818 if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
1827 if (!(after = search_func(
ast_str_buffer(before), delimiter[0]))) {
1851 static int unshift_push(
struct ast_channel *chan,
const char *cmd,
char *data,
const char *new_value)
1853 #define beginning (cmd[0] == 'U')
1854 char delimiter[2] =
",", *varsubst;
1856 struct ast_str *buf, *previous_value;
1861 const char *stripped_var;
1870 if (ast_strlen_zero(args.var)) {
1871 ast_log(LOG_WARNING,
"%s requires a variable name\n", cmd);
1875 if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
1885 stripped_var = args.var + MIN(strspn(args.var,
"_"), 2);
1886 varsubst =
ast_alloca(strlen(stripped_var) + 4);
1887 sprintf(varsubst,
"${%s}", stripped_var);
1907 .write = unshift_push,
1912 .write = unshift_push,
1915 static int passthru(
struct ast_channel *chan,
const char *cmd,
char *data,
struct ast_str **buf, ssize_t len)
1926 #ifdef TEST_FRAMEWORK
1929 int i, res = AST_TEST_PASS;
1932 char expression[256];
1937 const char *expected;
1939 {
"abc,def,ghi,jkl",
"\\,",
"ghi",
"3"},
1940 {
"abc def ghi jkl",
" ",
"abc",
"1"},
1941 {
"abc/def/ghi/jkl",
"\\\\x2f",
"def",
"2"},
1942 {
"abc$def$ghi$jkl",
"",
"ghi",
"0"},
1943 {
"abc,def,ghi,jkl",
"-",
"",
"0"},
1944 {
"abc-def-ghi-jkl",
"-",
"mno",
"0"}
1949 info->name =
"func_FIELDNUM_test";
1950 info->category =
"/funcs/func_strings/";
1951 info->summary =
"Test FIELDNUM function";
1952 info->description =
"Verify FIELDNUM behavior";
1953 return AST_TEST_NOT_RUN;
1959 ast_test_status_update(
test,
"Unable to allocate dummy channel\n");
1960 return AST_TEST_FAIL;
1964 ast_test_status_update(
test,
"Unable to allocate dynamic string buffer\n");
1966 return AST_TEST_FAIL;
1969 for (i = 0; i < ARRAY_LEN(test_args); i++) {
1970 struct ast_var_t *var = ast_var_assign(
"FIELDS", test_args[i].fields);
1972 ast_test_status_update(
test,
"Out of memory\n");
1973 res = AST_TEST_FAIL;
1979 snprintf(expression,
sizeof(expression),
"${FIELDNUM(%s,%s,%s)}", var->name, test_args[i].delim, test_args[i].field);
1983 ast_var_delete(var);
1986 ast_test_status_update(
test,
"Evaluation of '%s' returned '%s' instead of the expected value '%s'\n",
1988 res = AST_TEST_FAIL;
2001 int i, res = AST_TEST_PASS;
2004 char expression[256];
2006 const char *test_string;
2007 const char *find_chars;
2008 const char *replace_char;
2009 const char *expected;
2011 {
"abc,def",
"\\,",
"-",
"abc-def"},
2012 {
"abc,abc",
"bc",
"a",
"aaa,aaa"},
2013 {
"abc,def",
"x",
"?",
"abc,def"},
2014 {
"abc,def",
"\\,",
"",
"abcdef"}
2019 info->name =
"func_REPLACE_test";
2020 info->category =
"/funcs/func_strings/";
2021 info->summary =
"Test REPLACE function";
2022 info->description =
"Verify REPLACE behavior";
2023 return AST_TEST_NOT_RUN;
2029 ast_test_status_update(
test,
"Unable to allocate dummy channel\n");
2030 return AST_TEST_FAIL;
2034 ast_test_status_update(
test,
"Unable to allocate dynamic string buffer\n");
2036 return AST_TEST_FAIL;
2039 for (i = 0; i < ARRAY_LEN(test_args); i++) {
2040 struct ast_var_t *var = ast_var_assign(
"TEST_STRING", test_args[i].test_string);
2042 ast_test_status_update(
test,
"Out of memory\n");
2043 res = AST_TEST_FAIL;
2049 snprintf(expression,
sizeof(expression),
"${REPLACE(%s,%s,%s)}", var->name, test_args[i].find_chars, test_args[i].replace_char);
2053 ast_var_delete(var);
2056 ast_test_status_update(
test,
"Evaluation of '%s' returned '%s' instead of the expected value '%s'\n",
2058 res = AST_TEST_FAIL;
2071 int i, res = AST_TEST_PASS;
2072 const char *test_strings[][2] = {
2075 {
"\\x41-R",
"DAHDI"},
2076 {
"0-9A-Ca-c",
"0042133333A12212"},
2077 {
"0-9a-cA-C_+\\-",
"0042133333A12212"},
2083 info->name =
"func_FILTER_test";
2084 info->category =
"/funcs/func_strings/";
2085 info->summary =
"Test FILTER function";
2086 info->description =
"Verify FILTER behavior";
2087 return AST_TEST_NOT_RUN;
2092 for (i = 0; test_strings[i][0]; i++) {
2093 char tmp[256], tmp2[256] =
"";
2094 snprintf(tmp,
sizeof(tmp),
"${FILTER(%s,0042133333&DAHDI/g1/2212)}", test_strings[i][0]);
2095 pbx_substitute_variables_helper(NULL, tmp, tmp2,
sizeof(tmp2) - 1);
2096 if (strcmp(test_strings[i][1], tmp2)) {
2097 ast_test_status_update(
test,
"Format string '%s' substituted to '%s'. Expected '%s'.\n", test_strings[i][0], tmp2, test_strings[i][1]);
2098 res = AST_TEST_FAIL;
2106 int i, res = AST_TEST_PASS;
2110 const char *test_strings[][5] = {
2111 {
"Weasels have eaten my telephone system",
"have eaten my",
"are eating our",
"",
"Weasels are eating our telephone system"},
2112 {
"Did you know twenty plus two is twenty-two?",
"twenty",
"thirty", NULL,
"Did you know thirty plus two is thirty-two?"},
2113 {
"foofoofoofoofoofoofoo",
"foofoo",
"bar", NULL,
"barbarbarfoo"},
2114 {
"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."},
2115 {
"One and one and one is three",
"and",
"plus",
"1",
"One plus one and one is three"},
2116 {
"",
"fhqwagads",
"spelunker", NULL,
""},
2117 {
"Part of this string is missing.",
"missing", NULL, NULL,
"Part of this string is ."},
2118 {
"'Accidentally' left off a bunch of stuff.", NULL, NULL, NULL,
""},
2119 {
"This test will also error.",
"",
"",
"",
""},
2120 {
"This is an \"escape character\" test.",
"\\\"escape character\\\"",
"evil", NULL,
"This is an evil test."}
2125 info->name =
"func_STRREPLACE_test";
2126 info->category =
"/funcs/func_strings/";
2127 info->summary =
"Test STRREPLACE function";
2128 info->description =
"Verify STRREPLACE behavior";
2129 return AST_TEST_NOT_RUN;
2135 ast_test_status_update(
test,
"Unable to allocate dummy channel\n");
2136 return AST_TEST_FAIL;
2140 ast_test_status_update(
test,
"Unable to allocate dynamic string buffer\n");
2142 return AST_TEST_FAIL;
2145 for (i = 0; i < ARRAY_LEN(test_strings); i++) {
2146 char tmp[512], tmp2[512] =
"";
2148 struct ast_var_t *var = ast_var_assign(
"test_string", test_strings[i][0]);
2150 ast_test_status_update(
test,
"Unable to allocate variable\n");
2153 return AST_TEST_FAIL;
2158 if (test_strings[i][3]) {
2159 snprintf(tmp,
sizeof(tmp),
"${STRREPLACE(%s,%s,%s,%s)}",
"test_string", test_strings[i][1], test_strings[i][2], test_strings[i][3]);
2160 }
else if (test_strings[i][2]) {
2161 snprintf(tmp,
sizeof(tmp),
"${STRREPLACE(%s,%s,%s)}",
"test_string", test_strings[i][1], test_strings[i][2]);
2162 }
else if (test_strings[i][1]) {
2163 snprintf(tmp,
sizeof(tmp),
"${STRREPLACE(%s,%s)}",
"test_string", test_strings[i][1]);
2165 snprintf(tmp,
sizeof(tmp),
"${STRREPLACE(%s)}",
"test_string");
2169 ast_test_status_update(
test,
"Format string '%s' substituted to '%s'. Expected '%s'.\n", test_strings[i][0], tmp2, test_strings[i][4]);
2170 res = AST_TEST_FAIL;
2182 int i, res = AST_TEST_PASS;
2186 const char *test_strings[][5] = {
2189 {
"212",
"w",
"2w1w2"},
2190 {
"212",
"55",
"2551552"},
2191 {
"212",
" ",
"2 1 2"},
2194 {
"abcdefg",
"_",
"a_b_c_d_e_f_g"},
2197 {
"AAA",
"B",
"ABABA"},
2202 info->name =
"func_STRBETWEEN";
2203 info->category =
"/funcs/func_strings/";
2204 info->summary =
"Test STRBETWEEN function";
2205 info->description =
"Verify STRBETWEEN behavior";
2206 return AST_TEST_NOT_RUN;
2212 ast_test_status_update(
test,
"Unable to allocate dummy channel\n");
2213 return AST_TEST_FAIL;
2217 ast_test_status_update(
test,
"Unable to allocate dynamic string buffer\n");
2219 return AST_TEST_FAIL;
2222 for (i = 0; i < ARRAY_LEN(test_strings); i++) {
2223 char tmp[512], tmp2[512] =
"";
2225 struct ast_var_t *var = ast_var_assign(
"test_string", test_strings[i][0]);
2227 ast_test_status_update(
test,
"Unable to allocate variable\n");
2230 return AST_TEST_FAIL;
2235 if (test_strings[i][1]) {
2236 snprintf(tmp,
sizeof(tmp),
"${STRBETWEEN(%s,%s)}",
"test_string", test_strings[i][1]);
2238 snprintf(tmp,
sizeof(tmp),
"${STRBETWEEN(%s)}",
"test_string");
2242 ast_test_status_update(
test,
"Format string '%s' substituted to '%s'. Expected '%s'.\n", test_strings[i][0], tmp2, test_strings[i][2]);
2243 res = AST_TEST_FAIL;
2255 int i, res = AST_TEST_PASS;
2259 const char *test_strings[][5] = {
2260 {
"TRIM",
" abcd ",
"abcd"},
2261 {
"LTRIM",
" abcd ",
"abcd "},
2262 {
"RTRIM",
" abcd ",
" abcd"},
2263 {
"TRIM",
"abcd",
"abcd"},
2264 {
"TRIM",
" a b c d ",
"a b c d"},
2269 info->name =
"func_TRIM";
2270 info->category =
"/funcs/func_strings/";
2271 info->summary =
"Test TRIM functions";
2272 info->description =
"Verify TRIM behavior";
2273 return AST_TEST_NOT_RUN;
2279 ast_test_status_update(
test,
"Unable to allocate dummy channel\n");
2280 return AST_TEST_FAIL;
2284 ast_test_status_update(
test,
"Unable to allocate dynamic string buffer\n");
2286 return AST_TEST_FAIL;
2289 for (i = 0; i < ARRAY_LEN(test_strings); i++) {
2290 char tmp[512], tmp2[512] =
"";
2292 snprintf(tmp,
sizeof(tmp),
"${%s(%s)}", test_strings[i][0], test_strings[i][1]);
2295 ast_test_status_update(
test,
"Format string '%s' substituted to '%s'. Expected '%s'.\n", test_strings[i][0], tmp2, test_strings[i][2]);
2296 res = AST_TEST_FAIL;
2307 static int unload_module(
void)
2311 AST_TEST_UNREGISTER(test_FIELDNUM);
2312 AST_TEST_UNREGISTER(test_REPLACE);
2313 AST_TEST_UNREGISTER(test_FILTER);
2314 AST_TEST_UNREGISTER(test_STRREPLACE);
2315 AST_TEST_UNREGISTER(test_STRBETWEEN);
2316 AST_TEST_UNREGISTER(test_TRIM);
2350 static int load_module(
void)
2354 AST_TEST_REGISTER(test_FIELDNUM);
2355 AST_TEST_REGISTER(test_REPLACE);
2356 AST_TEST_REGISTER(test_FILTER);
2357 AST_TEST_REGISTER(test_STRREPLACE);
2358 AST_TEST_REGISTER(test_STRBETWEEN);
2359 AST_TEST_REGISTER(test_TRIM);
2393 AST_MODULE_INFO_STANDARD(
ASTERISK_GPL_KEY,
"String handling dialplan functions");
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Main Channel structure associated with a channel.
Asterisk main include file. File version handling, generic pbx functions.
char * ast_get_encoded_str(const char *stream, char *result, size_t result_len)
Decode a stream of encoded control or extended ASCII characters.
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
struct ast_channel * ast_channel_release(struct ast_channel *chan)
Unlink and release reference to a channel.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
int ast_get_timeval(const char *src, struct timeval *tv, struct timeval _default, int *consumed)
Parse a time (float) string.
int ast_unregister_application(const char *app)
Unregister an application.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
Custom localtime functions for multiple timezones.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
General Asterisk PBX channel definitions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ast_dummy_channel_alloc()
Create a fake channel structure.
char * ast_str_append_substr(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc)
Append a non-NULL terminated substring to the end of a dynamic string.
Data structure associated with a custom dialplan function.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
#define ast_debug(level,...)
Log a DEBUG message.
int ast_get_encoded_char(const char *stream, char *result, size_t *consumed)
Decode an encoded control or extended ASCII character.
Core PBX routines and definitions.
char * ast_strptime(const char *s, const char *format, struct ast_tm *tm)
Special version of strptime(3) which places the answer in the common structure ast_tm. Also, unlike strptime(3), ast_strptime() initializes its memory prior to use.
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Support for dynamic strings.
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the 'nonstandard' argument separation process for an application.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
struct timeval ast_mktime(struct ast_tm *const tmp, const char *zone)
Timezone-independent version of mktime(3).
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
void ast_str_update(struct ast_str *buf)
Update the length of the buffer, after using ast_str merely as a buffer.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
#define AST_TEST_DEFINE(hdr)
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define ast_custom_function_register(acf)
Register a custom function.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
#define AST_APP_ARG(name)
Define an application argument.