44 * Copyright (C) 2005-2006, Digium, Inc.
55 * Portions Copyright (C) 2005, Tilghman Lesher. All rights reserved.
66 * Portions Copyright (C) 2005, Anthony Minessale II
7+ * Portions Copyright (C) 2021, Naveen Albert
78 *
89 * See http://www.asterisk.org for more information about
910 * the Asterisk project. Please do not directly contact
2223 *
2324 * \author Tilghman Lesher
2425 * \author Anothony Minessale II
26+ * \author Naveen Albert
2527 * \ingroup functions
2628 */
2729
@@ -152,6 +154,24 @@ AST_THREADSTORAGE(tmp_buf);
152154 <note><para>The replacement only occurs in the output. The original variable is not altered.</para></note>
153155 </description>
154156 </function>
157+ <function name="STRBETWEEN" language="en_US">
158+ <synopsis>
159+ Inserts a substring between each character in a string.
160+ </synopsis>
161+ <syntax>
162+ <parameter name="varname" required="true" />
163+ <parameter name="insert-string" required="true" />
164+ </syntax>
165+ <description>
166+ <para>Inserts a substring <replaceable>find-string</replaceable> between each character in
167+ <replaceable>varname</replaceable>.</para>
168+ <note><para>The replacement only occurs in the output. The original variable is not altered.</para></note>
169+ <example title="Add half-second pause between dialed digits">
170+ same => n,Set(digits=5551212)
171+ same => n,SendDTMF(${STRBETWEEN(digits,w)) ; this will send 5w5w5w1w2w1w2
172+ </example>
173+ </description>
174+ </function>
155175 <function name="PASSTHRU" language="en_US">
156176 <synopsis>
157177 Pass the given argument back as a value.
@@ -945,6 +965,53 @@ static struct ast_custom_function strreplace_function = {
945965 .read2 = strreplace ,
946966};
947967
968+ static int strbetween (struct ast_channel * chan , const char * cmd , char * data , struct ast_str * * buf , ssize_t len )
969+ {
970+ int c , origsize ;
971+ char * varsubstr , * origstr ;
972+ struct ast_str * str = ast_str_thread_get (& result_buf , 16 ); /* Holds the data obtained from varname */
973+
974+ AST_DECLARE_APP_ARGS (args ,
975+ AST_APP_ARG (varname );
976+ AST_APP_ARG (insert_string );
977+ AST_APP_ARG (other ); /* Any remining unused arguments */
978+ );
979+
980+ ast_str_reset (* buf );
981+
982+ if (!str ) {
983+ ast_log (LOG_ERROR , "Couldn't obtain string\n" );
984+ return -1 ;
985+ }
986+
987+ AST_STANDARD_APP_ARGS (args , data );
988+
989+ if (args .argc != 2 || ast_strlen_zero (args .varname )) {
990+ ast_log (LOG_ERROR , "Usage: %s(<varname>,<insert-string>)\n" , cmd );
991+ return -1 ;
992+ }
993+
994+ varsubstr = ast_alloca (strlen (args .varname ) + 4 );
995+ sprintf (varsubstr , "${%s}" , args .varname );
996+ ast_str_substitute_variables (& str , 0 , chan , varsubstr );
997+ origstr = ast_str_buffer (str );
998+ origsize = strlen (origstr );
999+ for (c = 0 ; c < origsize ; c ++ ) {
1000+ ast_str_append (buf , len , "%c" , origstr [c ]);
1001+ /* no insert after the last character */
1002+ if (c < (origsize - 1 )) {
1003+ ast_str_append (buf , len , "%s" , args .insert_string );
1004+ }
1005+ }
1006+
1007+ return 0 ;
1008+ }
1009+
1010+ static struct ast_custom_function strbetween_function = {
1011+ .name = "STRBETWEEN" ,
1012+ .read2 = strbetween ,
1013+ };
1014+
9481015static int regex (struct ast_channel * chan , const char * cmd , char * parse , char * buf ,
9491016 size_t len )
9501017{
@@ -1953,6 +2020,79 @@ AST_TEST_DEFINE(test_STRREPLACE)
19532020
19542021 return res ;
19552022}
2023+
2024+ AST_TEST_DEFINE (test_STRBETWEEN )
2025+ {
2026+ int i , res = AST_TEST_PASS ;
2027+ struct ast_channel * chan ; /* dummy channel */
2028+ struct ast_str * str ; /* fancy string for holding comparing value */
2029+
2030+ const char * test_strings [][5 ] = {
2031+ {"0" , "w" , "0" },
2032+ {"30" , "w" , "3w0" },
2033+ {"212" , "w" , "2w1w2" },
2034+ {"212" , "55" , "2551552" },
2035+ {"212" , " " , "2 1 2" },
2036+ {"" , "w" , "" },
2037+ {"555" , "" , "555" },
2038+ {"abcdefg" , "_" , "a_b_c_d_e_f_g" },
2039+ {"A" , "A" , "A" },
2040+ {"AA" , "B" , "ABA" },
2041+ {"AAA" , "B" , "ABABA" },
2042+ };
2043+
2044+ switch (cmd ) {
2045+ case TEST_INIT :
2046+ info -> name = "func_STRBETWEEN" ;
2047+ info -> category = "/funcs/func_strings/" ;
2048+ info -> summary = "Test STRBETWEEN function" ;
2049+ info -> description = "Verify STRBETWEEN behavior" ;
2050+ return AST_TEST_NOT_RUN ;
2051+ case TEST_EXECUTE :
2052+ break ;
2053+ }
2054+
2055+ if (!(chan = ast_dummy_channel_alloc ())) {
2056+ ast_test_status_update (test , "Unable to allocate dummy channel\n" );
2057+ return AST_TEST_FAIL ;
2058+ }
2059+
2060+ if (!(str = ast_str_create (64 ))) {
2061+ ast_test_status_update (test , "Unable to allocate dynamic string buffer\n" );
2062+ ast_channel_release (chan );
2063+ return AST_TEST_FAIL ;
2064+ }
2065+
2066+ for (i = 0 ; i < ARRAY_LEN (test_strings ); i ++ ) {
2067+ char tmp [512 ], tmp2 [512 ] = "" ;
2068+
2069+ struct ast_var_t * var = ast_var_assign ("test_string" , test_strings [i ][0 ]);
2070+ if (!var ) {
2071+ ast_test_status_update (test , "Unable to allocate variable\n" );
2072+ ast_free (str );
2073+ ast_channel_release (chan );
2074+ return AST_TEST_FAIL ;
2075+ }
2076+
2077+ AST_LIST_INSERT_HEAD (ast_channel_varshead (chan ), var , entries );
2078+
2079+ if (test_strings [i ][1 ]) {
2080+ snprintf (tmp , sizeof (tmp ), "${STRBETWEEN(%s,%s)}" , "test_string" , test_strings [i ][1 ]);
2081+ } else {
2082+ snprintf (tmp , sizeof (tmp ), "${STRBETWEEN(%s)}" , "test_string" );
2083+ }
2084+ ast_str_substitute_variables (& str , 0 , chan , tmp );
2085+ if (strcmp (test_strings [i ][2 ], ast_str_buffer (str ))) {
2086+ ast_test_status_update (test , "Format string '%s' substituted to '%s'. Expected '%s'.\n" , test_strings [i ][0 ], tmp2 , test_strings [i ][2 ]);
2087+ res = AST_TEST_FAIL ;
2088+ }
2089+ }
2090+
2091+ ast_free (str );
2092+ ast_channel_release (chan );
2093+
2094+ return res ;
2095+ }
19562096#endif
19572097
19582098static int unload_module (void )
@@ -1963,11 +2103,13 @@ static int unload_module(void)
19632103 AST_TEST_UNREGISTER (test_REPLACE );
19642104 AST_TEST_UNREGISTER (test_FILTER );
19652105 AST_TEST_UNREGISTER (test_STRREPLACE );
2106+ AST_TEST_UNREGISTER (test_STRBETWEEN );
19662107 res |= ast_custom_function_unregister (& fieldqty_function );
19672108 res |= ast_custom_function_unregister (& fieldnum_function );
19682109 res |= ast_custom_function_unregister (& filter_function );
19692110 res |= ast_custom_function_unregister (& replace_function );
19702111 res |= ast_custom_function_unregister (& strreplace_function );
2112+ res |= ast_custom_function_unregister (& strbetween_function );
19712113 res |= ast_custom_function_unregister (& listfilter_function );
19722114 res |= ast_custom_function_unregister (& regex_function );
19732115 res |= ast_custom_function_unregister (& array_function );
@@ -2000,11 +2142,13 @@ static int load_module(void)
20002142 AST_TEST_REGISTER (test_REPLACE );
20012143 AST_TEST_REGISTER (test_FILTER );
20022144 AST_TEST_REGISTER (test_STRREPLACE );
2145+ AST_TEST_REGISTER (test_STRBETWEEN );
20032146 res |= ast_custom_function_register (& fieldqty_function );
20042147 res |= ast_custom_function_register (& fieldnum_function );
20052148 res |= ast_custom_function_register (& filter_function );
20062149 res |= ast_custom_function_register (& replace_function );
20072150 res |= ast_custom_function_register (& strreplace_function );
2151+ res |= ast_custom_function_register (& strbetween_function );
20082152 res |= ast_custom_function_register (& listfilter_function );
20092153 res |= ast_custom_function_register (& regex_function );
20102154 res |= ast_custom_function_register (& array_function );
0 commit comments