Asterisk - The Open Source Telephony Project  18.5.0
Functions
strings.c File Reference

String manipulation API. More...

#include "asterisk.h"
#include <regex.h>
#include "asterisk/strings.h"
#include "asterisk/pbx.h"
#include "asterisk/vector.h"
Include dependency graph for strings.c:

Go to the source code of this file.

Functions

int __ast_str_helper (struct ast_str **buf, ssize_t max_len, int append, const char *fmt, va_list ap, const char *file, int lineno, const char *function)
 Core functionality of ast_str_(set|append)_va. More...
 
char * __ast_str_helper2 (struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc, int append, int escapecommas)
 
char * ast_generate_random_string (char *buf, size_t size)
 Create a pseudo-random string of a fixed length. More...
 
char * ast_read_line_from_buffer (char **buffer)
 Read lines from a string buffer. More...
 
int ast_str_container_add (struct ao2_container *str_container, const char *add)
 Adds a string to a string container allocated by ast_str_container_alloc. More...
 
struct ao2_containerast_str_container_alloc_options (enum ao2_alloc_opts opts, int buckets)
 Allocates a hash container for bare strings. More...
 
void ast_str_container_remove (struct ao2_container *str_container, const char *remove)
 Removes a string from a string container allocated by ast_str_container_alloc. More...
 
int ast_strings_equal (const char *str1, const char *str2)
 Compare strings for equality checking for NULL. More...
 
int ast_strings_match (const char *left, const char *op, const char *right)
 Compares 2 strings using realtime-style operators. More...
 
int ast_vector_string_split (struct ast_vector_string *dest, const char *input, const char *delim, int flags, int(*excludes_cmp)(const char *s1, const char *s2))
 Append a string vector by splitting a string. More...
 
static int str_cmp (void *lhs, void *rhs, int flags)
 
static int str_hash (const void *obj, const int flags)
 
static int str_sort (const void *lhs, const void *rhs, int flags)
 

Detailed Description

String manipulation API.

Author
Tilghman Lesher tilgh.nosp@m.man@.nosp@m.digiu.nosp@m.m.co.nosp@m.m

Definition in file strings.c.

Function Documentation

◆ __ast_str_helper()

int __ast_str_helper ( struct ast_str **  buf,
ssize_t  max_len,
int  append,
const char *  fmt,
va_list  ap,
const char *  file,
int  lineno,
const char *  function 
)

Core functionality of ast_str_(set|append)_va.

core handler for dynamic strings. This is not meant to be called directly, but rather through the various wrapper macros ast_str_set(...) ast_str_append(...) ast_str_set_va(...) ast_str_append_va(...)

Definition at line 55 of file strings.c.

References _ast_str_make_space(), AST_DYNSTR_BUILD_FAILED, ast_log_safe(), if(), and LOG_VERBOSE.

58 {
59  int res;
60  int added;
61  int need;
62  int offset = (append && (*buf)->__AST_STR_LEN) ? (*buf)->__AST_STR_USED : 0;
63  va_list aq;
64 
65  if (max_len < 0) {
66  max_len = (*buf)->__AST_STR_LEN; /* don't exceed the allocated space */
67  }
68 
69  do {
70  va_copy(aq, ap);
71  res = vsnprintf((*buf)->__AST_STR_STR + offset, (*buf)->__AST_STR_LEN - offset, fmt, aq);
72  va_end(aq);
73 
74  if (res < 0) {
75  /*
76  * vsnprintf write to string failed.
77  * I don't think this is possible with a memory buffer.
78  */
80  added = 0;
81  break;
82  }
83 
84  /*
85  * vsnprintf returns how much space we used or would need.
86  * Remember that vsnprintf does not count the nil terminator
87  * so we must add 1.
88  */
89  added = res;
90  need = offset + added + 1;
91  if (need <= (*buf)->__AST_STR_LEN
92  || (max_len && max_len <= (*buf)->__AST_STR_LEN)) {
93  /*
94  * There was enough room for the string or we are not
95  * allowed to try growing the string buffer.
96  */
97  break;
98  }
99 
100  /* Reallocate the buffer and try again. */
101  if (max_len == 0) {
102  /* unbounded, give more room for next time */
103  need += 16 + need / 4;
104  } else if (max_len < need) {
105  /* truncate as needed */
106  need = max_len;
107  }
108 
109  if (_ast_str_make_space(buf, need, file, lineno, function)) {
110  ast_log_safe(LOG_VERBOSE, "failed to extend from %d to %d\n",
111  (int) (*buf)->__AST_STR_LEN, need);
112 
114  break;
115  }
116  } while (1);
117 
118  /* Update space used, keep in mind truncation may be necessary. */
119  (*buf)->__AST_STR_USED = ((*buf)->__AST_STR_LEN <= offset + added)
120  ? (*buf)->__AST_STR_LEN - 1
121  : offset + added;
122 
123  /* Ensure that the string is terminated. */
124  (*buf)->__AST_STR_STR[(*buf)->__AST_STR_USED] = '\0';
125 
126  return res;
127 }
if(!yyg->yy_init)
Definition: ast_expr2f.c:868
void ast_log_safe(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message with protection against recursion.
Definition: logger.c:2123
int _ast_str_make_space(struct ast_str **buf, size_t new_len, const char *file, int lineno, const char *function)
Definition: strings.h:779
#define LOG_VERBOSE
Definition: logger.h:296

◆ __ast_str_helper2()

char* __ast_str_helper2 ( struct ast_str **  buf,
ssize_t  maxlen,
const char *  src,
size_t  maxsrc,
int  append,
int  escapecommas 
)

Definition at line 129 of file strings.c.

References ast_str::__AST_STR_LEN, ast_str_make_space, and if().

Referenced by ast_str_append_substr(), ast_str_append_va(), ast_str_set_escapecommas(), and ast_str_set_substr().

130 {
131  int dynamic = 0;
132  char *ptr = append ? &((*buf)->__AST_STR_STR[(*buf)->__AST_STR_USED]) : (*buf)->__AST_STR_STR;
133 
134  if (maxlen < 1) {
135  if (maxlen == 0) {
136  dynamic = 1;
137  }
138  maxlen = (*buf)->__AST_STR_LEN;
139  }
140 
141  while (*src && maxsrc && maxlen && (!escapecommas || (maxlen - 1))) {
142  if (escapecommas && (*src == '\\' || *src == ',')) {
143  *ptr++ = '\\';
144  maxlen--;
145  (*buf)->__AST_STR_USED++;
146  }
147  *ptr++ = *src++;
148  maxsrc--;
149  maxlen--;
150  (*buf)->__AST_STR_USED++;
151 
152  if ((ptr >= (*buf)->__AST_STR_STR + (*buf)->__AST_STR_LEN - 3) ||
153  (dynamic && (!maxlen || (escapecommas && !(maxlen - 1))))) {
154  char *oldbase = (*buf)->__AST_STR_STR;
155  size_t old = (*buf)->__AST_STR_LEN;
156  if (ast_str_make_space(buf, (*buf)->__AST_STR_LEN * 2)) {
157  /* If the buffer can't be extended, end it. */
158  break;
159  }
160  /* What we extended the buffer by */
161  maxlen = old;
162 
163  ptr += (*buf)->__AST_STR_STR - oldbase;
164  }
165  }
166  if (__builtin_expect(!maxlen, 0)) {
167  ptr--;
168  }
169  *ptr = '\0';
170  return (*buf)->__AST_STR_STR;
171 }
#define ast_str_make_space(buf, new_len)
Definition: strings.h:780
if(!yyg->yy_init)
Definition: ast_expr2f.c:868
size_t __AST_STR_LEN
Definition: strings.h:585

◆ ast_generate_random_string()

char* ast_generate_random_string ( char *  buf,
size_t  size 
)

Create a pseudo-random string of a fixed length.

This function is useful for generating a string whose randomness does not need to be across all time and space, does not need to be cryptographically secure, and needs to fit in a limited space.

This function will write a null byte at the final position in the buffer (buf[size - 1]). So if you pass in a size of 10, then this will generate a random 9-character string.

Parameters
bufBuffer to write random string into.
sizeThe size of the buffer.
Returns
A pointer to buf

Definition at line 227 of file strings.c.

References ast_random(), and buf.

Referenced by add_rlmi_resource(), create_multipart_body(), generate_content_id_hdr(), and sip_outbound_registration_regc_alloc().

228 {
229  int i;
230 
231  for (i = 0; i < size - 1; ++i) {
232  buf[i] = 'a' + (ast_random() % 26);
233  }
234  buf[i] = '\0';
235 
236  return buf;
237 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
long int ast_random(void)
Definition: main/utils.c:2064

◆ ast_read_line_from_buffer()

char* ast_read_line_from_buffer ( char **  buffer)

Read lines from a string buffer.

Since
13.18.0
Parameters
buffer[IN/OUT] A pointer to a char * string with either Unix or Windows line endings
Returns
The "next" line
Warning
The original string and *buffer will be modified.

Both '
' and '
' are treated as single delimiters but consecutive occurrances of the delimiters are NOT considered to be a single delimiter. This preserves blank lines in the input.

MacOS line endings ('') are not supported at this time.

Definition at line 372 of file strings.c.

References NULL.

Referenced by parse_simple_message_summary().

373 {
374  char *start = *buffer;
375 
376  if (!buffer || !*buffer || *(*buffer) == '\0') {
377  return NULL;
378  }
379 
380  while (*(*buffer) && *(*buffer) != '\n' ) {
381  (*buffer)++;
382  }
383 
384  *(*buffer) = '\0';
385  if (*(*buffer - 1) == '\r') {
386  *(*buffer - 1) = '\0';
387  }
388  (*buffer)++;
389 
390  return start;
391 }
#define NULL
Definition: resample.c:96

◆ ast_str_container_add()

int ast_str_container_add ( struct ao2_container str_container,
const char *  add 
)

Adds a string to a string container allocated by ast_str_container_alloc.

Since
12
Parameters
str_containerThe container to which to add a string
addThe string to add to the container
Return values
zeroon success
non-zeroif the operation failed

Definition at line 206 of file strings.c.

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_link, ao2_ref, and NULL.

Referenced by add_media_cb(), add_variant_cb(), append_name(), apps_handler(), ast_bridge_snapshot_create(), ast_dns_get_nameservers(), ast_endpoint_add_channel(), AST_TEST_DEFINE(), complete_ari_app(), custom_nameserver_handler(), declined_handler(), event_session_alloc(), get_languages(), ip_identify_match_handler(), load_module(), test_cel_peer_strings_match(), and topic_add_subscription().

207 {
208  char *ao2_add;
209 
210  /* The ao2_add object is immutable so it doesn't need a lock of its own. */
211  ao2_add = ao2_alloc_options(strlen(add) + 1, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
212  if (!ao2_add) {
213  return -1;
214  }
215  strcpy(ao2_add, add);/* Safe */
216 
217  ao2_link(str_container, ao2_add);
218  ao2_ref(ao2_add, -1);
219  return 0;
220 }
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:406
#define NULL
Definition: resample.c:96
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ ast_str_container_alloc_options()

struct ao2_container* ast_str_container_alloc_options ( enum ao2_alloc_opts  opts,
int  buckets 
)

Allocates a hash container for bare strings.

Since
12
Parameters
optsOptions to be provided to the container
bucketsThe number of buckets to use for the hash container
Return values
AO2container for strings
NULLif allocation failed

Definition at line 201 of file strings.c.

References ao2_container_alloc_hash, str_cmp(), str_hash(), and str_sort().

Referenced by ast_dns_get_nameservers(), custom_nameserver_handler(), endpoint_internal_create(), and ip_identify_match_handler().

202 {
203  return ao2_container_alloc_hash(opts, 0, buckets, str_hash, str_sort, str_cmp);
204 }
static int str_cmp(void *lhs, void *rhs, int flags)
Definition: strings.c:187
static int str_sort(const void *lhs, const void *rhs, int flags)
Definition: strings.c:178
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
static int str_hash(const void *obj, const int flags)
Definition: strings.c:173

◆ ast_str_container_remove()

void ast_str_container_remove ( struct ao2_container str_container,
const char *  remove 
)

Removes a string from a string container allocated by ast_str_container_alloc.

Since
12
Parameters
str_containerThe container from which to remove a string
removeThe string to remove from the container

Definition at line 222 of file strings.c.

References ao2_find, OBJ_NODATA, OBJ_SEARCH_KEY, and OBJ_UNLINK.

Referenced by endpoint_cache_clear(), test_cel_peer_strings_match(), and topic_remove_subscription().

223 {
224  ao2_find(str_container, remove, OBJ_SEARCH_KEY | OBJ_NODATA | OBJ_UNLINK);
225 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756

◆ ast_strings_equal()

int ast_strings_equal ( const char *  str1,
const char *  str2 
)

Compare strings for equality checking for NULL.

Since
16.3.0

This function considers NULL values as non-strings, thus a false condition. This means that it will return false if one, or both of the given values are NULL (i.e. two NULLs are not equal strings).

Parameters
str1The string to compare to str2
str2The string to compare to str1
Returns
true if valid strings and equal, false otherwise.

Definition at line 239 of file strings.c.

Referenced by app_event_filter_matched(), is_media_state_valid(), load_realtime_musiconhold(), resolve_refresh_media_states(), and set_outbound_authentication_credentials().

240 {
241  if (!str1 || !str2) {
242  return 0;
243  }
244 
245  return str1 == str2 || !strcmp(str1, str2);
246 }

◆ ast_strings_match()

int ast_strings_match ( const char *  left,
const char *  op,
const char *  right 
)

Compares 2 strings using realtime-style operators.

Since
13.9.0
Parameters
leftThe left side of the equation
opThe operator to apply
rightThe right side of the equation
Return values
1matches
0doesn't match

Operators: "=", "!=", "<", "<=", ">", ">=": If both left and right can be converted to float, then they will be compared as such. Otherwise the result will be derived from strcmp(left, right). "regex": The right value will be compiled as a regular expression and matched against the left value. "like": Any '' character in the right value will be converted to '.*' and the resulting string will be handled as a regex. NULL , "": If the right value starts and ends with a '/' then it will be processed as a regex. Otherwise, same as "=".

Definition at line 248 of file strings.c.

References ast_str_alloca, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_strdupa, ast_strlen_zero, NULL, regex(), and strsep().

Referenced by AST_TEST_DEFINE(), and ast_variables_match().

249 {
250  char *internal_op = (char *)op;
251  char *internal_right = (char *)right;
252  double left_num;
253  double right_num;
254  int scan_numeric = 0;
255 
256  if (!(left && right)) {
257  return 0;
258  }
259 
260  if (ast_strlen_zero(op)) {
261  if (ast_strlen_zero(left) && ast_strlen_zero(right)) {
262  return 1;
263  }
264 
265  if (strlen(right) >= 2 && right[0] == '/' && right[strlen(right) - 1] == '/') {
266  internal_op = "regex";
267  internal_right = ast_strdupa(right);
268  /* strip the leading and trailing '/' */
269  internal_right++;
270  internal_right[strlen(internal_right) - 1] = '\0';
271  goto regex;
272  } else {
273  internal_op = "=";
274  goto equals;
275  }
276  }
277 
278  if (!strcasecmp(op, "like")) {
279  char *tok;
280  struct ast_str *buffer = ast_str_alloca(128);
281 
282  if (!strchr(right, '%')) {
283  return !strcmp(left, right);
284  } else {
285  internal_op = "regex";
286  internal_right = ast_strdupa(right);
287  tok = strsep(&internal_right, "%");
288  ast_str_set(&buffer, 0, "^%s", tok);
289 
290  while ((tok = strsep(&internal_right, "%"))) {
291  ast_str_append(&buffer, 0, ".*%s", tok);
292  }
293  ast_str_append(&buffer, 0, "%s", "$");
294 
295  internal_right = ast_str_buffer(buffer);
296  /* fall through to regex */
297  }
298  }
299 
300 regex:
301  if (!strcasecmp(internal_op, "regex")) {
302  regex_t expression;
303  int rc;
304 
305  if (regcomp(&expression, internal_right, REG_EXTENDED | REG_NOSUB)) {
306  return 0;
307  }
308 
309  rc = regexec(&expression, left, 0, NULL, 0);
310  regfree(&expression);
311  return !rc;
312  }
313 
314 equals:
315  scan_numeric = (sscanf(left, "%lf", &left_num) > 0 && sscanf(internal_right, "%lf", &right_num) > 0);
316 
317  if (internal_op[0] == '=') {
318  if (ast_strlen_zero(left) && ast_strlen_zero(internal_right)) {
319  return 1;
320  }
321 
322  if (scan_numeric) {
323  return (left_num == right_num);
324  } else {
325  return (!strcmp(left, internal_right));
326  }
327  }
328 
329  if (internal_op[0] == '!' && internal_op[1] == '=') {
330  if (scan_numeric) {
331  return (left_num != right_num);
332  } else {
333  return !!strcmp(left, internal_right);
334  }
335  }
336 
337  if (internal_op[0] == '<') {
338  if (scan_numeric) {
339  if (internal_op[1] == '=') {
340  return (left_num <= right_num);
341  } else {
342  return (left_num < right_num);
343  }
344  } else {
345  if (internal_op[1] == '=') {
346  return strcmp(left, internal_right) <= 0;
347  } else {
348  return strcmp(left, internal_right) < 0;
349  }
350  }
351  }
352 
353  if (internal_op[0] == '>') {
354  if (scan_numeric) {
355  if (internal_op[1] == '=') {
356  return (left_num >= right_num);
357  } else {
358  return (left_num > right_num);
359  }
360  } else {
361  if (internal_op[1] == '=') {
362  return strcmp(left, internal_right) >= 0;
363  } else {
364  return strcmp(left, internal_right) > 0;
365  }
366  }
367  }
368 
369  return 0;
370 }
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
#define ast_str_alloca(init_len)
Definition: strings.h:800
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1065
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
Definition: func_strings.c:948
char * strsep(char **str, const char *delims)

◆ ast_vector_string_split()

int ast_vector_string_split ( struct ast_vector_string *  dest,
const char *  input,
const char *  delim,
int  flags,
int(*)(const char *s1, const char *s2)  excludes_cmp 
)

Append a string vector by splitting a string.

Parameters
destPointer to an initialized vector.
inputString buffer to split.
delimString delimeter passed to strsep.
flagsProcessing options defined by enum ast_vector_string_split_flags.
excludes_cmpNULL or a function like strcmp to exclude duplicate strings.
Return values
0Success
-1Failure
Note
All elements added to the vector are allocated. The caller is always responsible for calling ast_free on each element in the vector even after failure. It's possible for this function to successfully add some elements before failing.

Definition at line 393 of file strings.c.

References ast_assert, ast_free, ast_strdup, ast_strdupa, ast_strip(), ast_strlen_zero, AST_VECTOR_APPEND, AST_VECTOR_GET_CMP, AST_VECTOR_STRING_SPLIT_ALLOW_EMPTY, AST_VECTOR_STRING_SPLIT_NO_TRIM, buf, NULL, and strsep().

Referenced by module_post_register().

396 {
397  char *buf;
398  char *cur;
399  int no_trim = flags & AST_VECTOR_STRING_SPLIT_NO_TRIM;
400  int allow_empty = flags & AST_VECTOR_STRING_SPLIT_ALLOW_EMPTY;
401 
402  ast_assert(dest != NULL);
403  ast_assert(!ast_strlen_zero(delim));
404 
405  if (ast_strlen_zero(input)) {
406  return 0;
407  }
408 
409  buf = ast_strdupa(input);
410  while ((cur = strsep(&buf, delim))) {
411  if (!no_trim) {
412  cur = ast_strip(cur);
413  }
414 
415  if (!allow_empty && ast_strlen_zero(cur)) {
416  continue;
417  }
418 
419  if (excludes_cmp && AST_VECTOR_GET_CMP(dest, cur, !excludes_cmp)) {
420  continue;
421  }
422 
423  cur = ast_strdup(cur);
424  if (!cur || AST_VECTOR_APPEND(dest, cur)) {
425  ast_free(cur);
426 
427  return -1;
428  }
429  }
430 
431  return 0;
432 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define ast_assert(a)
Definition: utils.h:695
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
static int input(yyscan_t yyscanner)
Definition: ast_expr2f.c:1584
#define ast_strlen_zero(foo)
Definition: strings.h:52
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:219
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
#define ast_free(a)
Definition: astmm.h:182
#define AST_VECTOR_GET_CMP(vec, value, cmp)
Get an element from a vector that matches the given comparison.
Definition: vector.h:733
char * strsep(char **str, const char *delims)

◆ str_cmp()

static int str_cmp ( void *  lhs,
void *  rhs,
int  flags 
)
static

Definition at line 187 of file strings.c.

References CMP_MATCH, OBJ_SEARCH_MASK, and OBJ_SEARCH_PARTIAL_KEY.

Referenced by ast_str_container_alloc_options().

188 {
189  int cmp = 0;
190 
191  if ((flags & OBJ_SEARCH_MASK) == OBJ_SEARCH_PARTIAL_KEY) {
192  cmp = strncmp(lhs, rhs, strlen(rhs));
193  } else {
194  cmp = strcmp(lhs, rhs);
195  }
196 
197  return cmp ? 0 : CMP_MATCH;
198 }
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1120
Search option field mask.
Definition: astobj2.h:1076

◆ str_hash()

static int str_hash ( const void *  obj,
const int  flags 
)
static

Definition at line 173 of file strings.c.

References ast_str_hash().

Referenced by ast_str_container_alloc_options().

174 {
175  return ast_str_hash(obj);
176 }
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1206

◆ str_sort()

static int str_sort ( const void *  lhs,
const void *  rhs,
int  flags 
)
static

Definition at line 178 of file strings.c.

References OBJ_SEARCH_MASK, and OBJ_SEARCH_PARTIAL_KEY.

Referenced by ast_str_container_alloc_options().

179 {
180  if ((flags & OBJ_SEARCH_MASK) == OBJ_SEARCH_PARTIAL_KEY) {
181  return strncmp(lhs, rhs, strlen(rhs));
182  } else {
183  return strcmp(lhs, rhs);
184  }
185 }
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1120
Search option field mask.
Definition: astobj2.h:1076