--- funcs/func_strings.c.orig 2010-09-21 17:04:16.000000000 +0200 +++ funcs/func_strings.c 2010-09-21 16:45:45.000000000 +0200 @@ -91,6 +91,25 @@ \ + + + Replace occurrences of string in a variable with another string. + + + + + + + + + Iterates through a the string contained in the varname + replacing at most occurrences occurrences of + needle with replace-char. + If occurrences is not specified, it defaults to all. + The replacement only occurs in the output. The original variable is not + altered. + + Check string against a regular expression. @@ -505,6 +524,117 @@ .read = filter, }; +/* Taken from https://issues.asterisk.org/file_download.php?file_id=24946&type=bug */ +static char *generic_strreplace(char const *haystack, char const *needle, char const *replacement, char *dst, size_t len, size_t occurrences) +{ + size_t haystack_len = strlen(haystack); + size_t needle_len = strlen(needle); + size_t replacement_len = strlen(replacement); + char const *needle_in_haystack; + char *orig_dst = dst; + + if (len == 0) + return NULL; + len -= 1; /* leave room for NUL byte */ + + while (1) { + size_t n; + needle_in_haystack = strstr(haystack, needle); + /* not found? we shall copy the whole thing */ + if (needle_in_haystack == NULL) + n = haystack_len; + else + n = needle_in_haystack - haystack; + /* not enough room? copy as much as we can and break */ + if (n > len) { + memcpy(dst, haystack, len); + dst += len; + break; + } + /* at least enough room to copy up to needle */ + memcpy(dst, haystack, n); + dst += n; + len -= n; + /* are we done? break */ + if (needle_in_haystack == NULL) { + break; + } + /* not enough room for replacement? break */ + if (len < replacement_len) { + break; + } + /* copy replacement and re-set haystack so we can continue */ + memcpy(dst, replacement, replacement_len); + dst += replacement_len; + len -= replacement_len; + haystack += (n + needle_len); + haystack_len -= (n + needle_len); + /* is there a limit on the occurrences? copy rest and stop */ + if (--occurrences == 0) { + size_t rest_len = len >= haystack_len ? haystack_len : len; + memcpy(dst, haystack, rest_len); + dst += rest_len; + break; + } + } + + *dst = '\0'; + return orig_dst; +} + +static int strreplace(struct ast_channel *chan, const char *cmd, char *parse, char *buf, + size_t len) +{ + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(varname); + AST_APP_ARG(needle); + AST_APP_ARG(replacement); + AST_APP_ARG(occurrences); + ); + char const *haystack; + char *needle, *replacement; + size_t occurrences = 0; + size_t tmp; + + AST_STANDARD_APP_ARGS(args, parse); + + if (args.argc < 3) { + ast_log(LOG_ERROR, "Usage: %s(,,[,])\n", cmd); + return -1; + } + + /* Decode escapes */ + tmp = strlen(args.needle) + 1; + needle = alloca(tmp); + ast_get_encoded_str(args.needle, needle, tmp); + tmp = strlen(args.replacement) + 1; + replacement = alloca(tmp); + ast_get_encoded_str(args.replacement, replacement, tmp); + + /* Fetch and check values */ + if (ast_strlen_zero(args.varname) || ast_strlen_zero(needle)) { + ast_log(LOG_ERROR, "The string to search for and the variable name must not be empty.\n"); + return -1; + } + haystack = pbx_builtin_getvar_helper(chan, args.varname); + if (haystack == NULL) { + ast_log(LOG_ERROR, "Variable %s not found.\n", args.varname); + return -1; + } + if (args.argc >= 4) { /* be forward compatible and allow 5+ args */ + occurrences = (size_t)atoi(args.occurrences); + } + + /* Do the actual work */ + generic_strreplace(haystack, needle, replacement, buf, len, occurrences); + return 0; +} + +static struct ast_custom_function strreplace_function = { + .name = "STRREPLACE", + .read = strreplace, +}; + static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len) { @@ -1004,6 +1134,7 @@ res |= ast_custom_function_unregister(&fieldqty_function); res |= ast_custom_function_unregister(&filter_function); res |= ast_custom_function_unregister(&listfilter_function); + res |= ast_custom_function_unregister(&strreplace_function); res |= ast_custom_function_unregister(®ex_function); res |= ast_custom_function_unregister(&array_function); res |= ast_custom_function_unregister("e_function); @@ -1029,6 +1160,7 @@ res |= ast_custom_function_register(&fieldqty_function); res |= ast_custom_function_register(&filter_function); res |= ast_custom_function_register(&listfilter_function); + res |= ast_custom_function_register(&strreplace_function); res |= ast_custom_function_register(®ex_function); res |= ast_custom_function_register(&array_function); res |= ast_custom_function_register("e_function);