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
7+ * Portions Copyright (C) 2021, 2022, Naveen Albert
88 *
99 * See http://www.asterisk.org for more information about
1010 * the Asterisk project. Please do not directly contact
@@ -183,6 +183,51 @@ AST_THREADSTORAGE(tmp_buf);
183183 </example>
184184 </description>
185185 </function>
186+ <function name="TRIM" language="en_US">
187+ <synopsis>
188+ Trim leading and trailing whitespace in a string
189+ </synopsis>
190+ <syntax>
191+ <parameter name="string" required="true" />
192+ </syntax>
193+ <description>
194+ <para>Replaces all leading and trailing whitespace in the provided string.</para>
195+ </description>
196+ <see-also>
197+ <ref type="function">LTRIM</ref>
198+ <ref type="function">RTRIM</ref>
199+ </see-also>
200+ </function>
201+ <function name="LTRIM" language="en_US">
202+ <synopsis>
203+ Trim leading whitespace in a string
204+ </synopsis>
205+ <syntax>
206+ <parameter name="string" required="true" />
207+ </syntax>
208+ <description>
209+ <para>Replaces all leading whitespace in the provided string.</para>
210+ </description>
211+ <see-also>
212+ <ref type="function">TRIM</ref>
213+ <ref type="function">RTRIM</ref>
214+ </see-also>
215+ </function>
216+ <function name="RTRIM" language="en_US">
217+ <synopsis>
218+ Trim trailing whitespace in a string
219+ </synopsis>
220+ <syntax>
221+ <parameter name="string" required="true" />
222+ </syntax>
223+ <description>
224+ <para>Replaces all trailing whitespace in the provided string.</para>
225+ </description>
226+ <see-also>
227+ <ref type="function">TRIM</ref>
228+ <ref type="function">LTRIM</ref>
229+ </see-also>
230+ </function>
186231 <function name="PASSTHRU" language="en_US">
187232 <synopsis>
188233 Pass the given argument back as a value.
@@ -1045,6 +1090,84 @@ static struct ast_custom_function strbetween_function = {
10451090 .read2 = strbetween ,
10461091};
10471092
1093+ #define ltrim (s ) while (isspace(*s)) s++;
1094+ #define rtrim (s ) { \
1095+ if (s) { \
1096+ char *back = s + strlen(s); \
1097+ while (back != s && isspace(*--back)); \
1098+ if (*s) { \
1099+ *(back + 1) = '\0'; \
1100+ } \
1101+ } \
1102+ }
1103+
1104+ static int function_trim (struct ast_channel * chan , const char * cmd , char * data , char * buf , size_t len )
1105+ {
1106+ char * c ;
1107+
1108+ if (ast_strlen_zero (data )) {
1109+ return -1 ;
1110+ }
1111+
1112+ c = ast_strdupa (data );
1113+ ltrim (c );
1114+ rtrim (c );
1115+
1116+ ast_copy_string (buf , c , len );
1117+
1118+ return 0 ;
1119+ }
1120+
1121+ static int function_ltrim (struct ast_channel * chan , const char * cmd , char * data , char * buf , size_t len )
1122+ {
1123+ char * c ;
1124+
1125+ if (ast_strlen_zero (data )) {
1126+ return -1 ;
1127+ }
1128+
1129+ c = data ;
1130+ ltrim (c );
1131+
1132+ ast_copy_string (buf , c , len );
1133+
1134+ return 0 ;
1135+ }
1136+
1137+ static int function_rtrim (struct ast_channel * chan , const char * cmd , char * data , char * buf , size_t len )
1138+ {
1139+ char * c ;
1140+
1141+ if (ast_strlen_zero (data )) {
1142+ return -1 ;
1143+ }
1144+
1145+ c = ast_strdupa (data );
1146+ rtrim (c );
1147+
1148+ ast_copy_string (buf , c , len );
1149+
1150+ return 0 ;
1151+ }
1152+
1153+ #undef ltrim
1154+ #undef rtrim
1155+
1156+ static struct ast_custom_function trim_function = {
1157+ .name = "TRIM" ,
1158+ .read = function_trim ,
1159+ };
1160+
1161+ static struct ast_custom_function ltrim_function = {
1162+ .name = "LTRIM" ,
1163+ .read = function_ltrim ,
1164+ };
1165+
1166+ static struct ast_custom_function rtrim_function = {
1167+ .name = "RTRIM" ,
1168+ .read = function_rtrim ,
1169+ };
1170+
10481171static int regex (struct ast_channel * chan , const char * cmd , char * parse , char * buf ,
10491172 size_t len )
10501173{
@@ -2126,6 +2249,59 @@ AST_TEST_DEFINE(test_STRBETWEEN)
21262249
21272250 return res ;
21282251}
2252+
2253+ AST_TEST_DEFINE (test_TRIM )
2254+ {
2255+ int i , res = AST_TEST_PASS ;
2256+ struct ast_channel * chan ; /* dummy channel */
2257+ struct ast_str * str ; /* fancy string for holding comparing value */
2258+
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" },
2265+ };
2266+
2267+ switch (cmd ) {
2268+ case TEST_INIT :
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 ;
2274+ case TEST_EXECUTE :
2275+ break ;
2276+ }
2277+
2278+ if (!(chan = ast_dummy_channel_alloc ())) {
2279+ ast_test_status_update (test , "Unable to allocate dummy channel\n" );
2280+ return AST_TEST_FAIL ;
2281+ }
2282+
2283+ if (!(str = ast_str_create (64 ))) {
2284+ ast_test_status_update (test , "Unable to allocate dynamic string buffer\n" );
2285+ ast_channel_release (chan );
2286+ return AST_TEST_FAIL ;
2287+ }
2288+
2289+ for (i = 0 ; i < ARRAY_LEN (test_strings ); i ++ ) {
2290+ char tmp [512 ], tmp2 [512 ] = "" ;
2291+
2292+ snprintf (tmp , sizeof (tmp ), "${%s(%s)}" , test_strings [i ][0 ], test_strings [i ][1 ]);
2293+ ast_str_substitute_variables (& str , 0 , chan , tmp );
2294+ if (strcmp (test_strings [i ][2 ], ast_str_buffer (str ))) {
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 ;
2297+ }
2298+ }
2299+
2300+ ast_free (str );
2301+ ast_channel_release (chan );
2302+
2303+ return res ;
2304+ }
21292305#endif
21302306
21312307static int unload_module (void )
@@ -2137,6 +2313,7 @@ static int unload_module(void)
21372313 AST_TEST_UNREGISTER (test_FILTER );
21382314 AST_TEST_UNREGISTER (test_STRREPLACE );
21392315 AST_TEST_UNREGISTER (test_STRBETWEEN );
2316+ AST_TEST_UNREGISTER (test_TRIM );
21402317 res |= ast_custom_function_unregister (& fieldqty_function );
21412318 res |= ast_custom_function_unregister (& fieldnum_function );
21422319 res |= ast_custom_function_unregister (& filter_function );
@@ -2163,6 +2340,9 @@ static int unload_module(void)
21632340 res |= ast_custom_function_unregister (& push_function );
21642341 res |= ast_custom_function_unregister (& unshift_function );
21652342 res |= ast_custom_function_unregister (& passthru_function );
2343+ res |= ast_custom_function_unregister (& trim_function );
2344+ res |= ast_custom_function_unregister (& ltrim_function );
2345+ res |= ast_custom_function_unregister (& rtrim_function );
21662346
21672347 return res ;
21682348}
@@ -2176,6 +2356,7 @@ static int load_module(void)
21762356 AST_TEST_REGISTER (test_FILTER );
21772357 AST_TEST_REGISTER (test_STRREPLACE );
21782358 AST_TEST_REGISTER (test_STRBETWEEN );
2359+ AST_TEST_REGISTER (test_TRIM );
21792360 res |= ast_custom_function_register (& fieldqty_function );
21802361 res |= ast_custom_function_register (& fieldnum_function );
21812362 res |= ast_custom_function_register (& filter_function );
@@ -2202,6 +2383,9 @@ static int load_module(void)
22022383 res |= ast_custom_function_register (& push_function );
22032384 res |= ast_custom_function_register (& unshift_function );
22042385 res |= ast_custom_function_register (& passthru_function );
2386+ res |= ast_custom_function_register (& trim_function );
2387+ res |= ast_custom_function_register (& ltrim_function );
2388+ res |= ast_custom_function_register (& rtrim_function );
22052389
22062390 return res ;
22072391}
0 commit comments