Asterisk - The Open Source Telephony Project  21.4.1
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"

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...
 
int ast_in_delimited_string (const char *needle, const char *haystack, char delim)
 Check if there is an exact match for 'needle' between delimiters in 'haystack'. 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

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, and ast_log_safe().

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 }
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:2475
int _ast_str_make_space(struct ast_str **buf, size_t new_len, const char *file, int lineno, const char *function)
Definition: strings.h:827
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 226 of file strings.c.

227 {
228  int i;
229 
230  for (i = 0; i < size - 1; ++i) {
231  buf[i] = 'a' + (ast_random() % 26);
232  }
233  buf[i] = '\0';
234 
235  return buf;
236 }
int ast_in_delimited_string ( const char *  needle,
const char *  haystack,
char  delim 
)

Check if there is an exact match for 'needle' between delimiters in 'haystack'.

Note
This will skip extra leading spaces between delimiters.
Parameters
needleThe string to search for
haystackThe string searched in
delimThe haystack delimiter
Return values
trueIf an exact match for needle is in haystack.
falseotherwise

Definition at line 433 of file strings.c.

References ast_skip_blanks().

Referenced by ast_json_object_create_vars().

434 {
435  const char *end;
436  unsigned long needle_size;
437 
438  ast_assert(haystack != NULL);
439 
440  if (!needle) {
441  return 0;
442  }
443 
444  needle_size = strlen(needle);
445  haystack = ast_skip_blanks(haystack);
446 
447  while ((end = strchr(haystack, delim))) {
448  if (needle_size == end - haystack && !strncmp(haystack, needle, needle_size)) {
449  return 1;
450  }
451  haystack = ast_skip_blanks(end + 1);
452  }
453 
454  return strcmp(haystack, needle) ? 0 : -1;
455 }
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:161
char* ast_read_line_from_buffer ( char **  buffer)

Read lines from a string buffer.

Since
13.18.0
Parameters
[in,out]bufferA 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 '\n' and '\r\n' are treated as single delimiters but consecutive occurrences of the delimiters are NOT considered to be a single delimiter. This preserves blank lines in the input.

macOS line endings ('\r') are not supported at this time.

Definition at line 371 of file strings.c.

372 {
373  char *start = *buffer;
374 
375  if (!buffer || !*buffer || *(*buffer) == '\0') {
376  return NULL;
377  }
378 
379  while (*(*buffer) && *(*buffer) != '\n' ) {
380  (*buffer)++;
381  }
382 
383  *(*buffer) = '\0';
384  if (*(*buffer - 1) == '\r') {
385  *(*buffer - 1) = '\0';
386  }
387  (*buffer)++;
388 
389  return start;
390 }
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 205 of file strings.c.

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_link, and ao2_ref.

Referenced by add_media_cb(), add_variant_cb(), ast_bridge_snapshot_create(), ast_dns_get_nameservers(), ast_endpoint_add_channel(), coreshowchannelmap_add_to_map(), event_session_alloc(), get_languages(), test_cel_peer_strings_match(), and topic_add_subscription().

206 {
207  char *ao2_add;
208 
209  /* The ao2_add object is immutable so it doesn't need a lock of its own. */
210  ao2_add = ao2_alloc_options(strlen(add) + 1, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
211  if (!ao2_add) {
212  return -1;
213  }
214  strcpy(ao2_add, add);/* Safe */
215 
216  ao2_link(str_container, ao2_add);
217  ao2_ref(ao2_add, -1);
218  return 0;
219 }
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
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
Returns
AO2 container for strings
Return values
NULLif allocation failed

Definition at line 200 of file strings.c.

References ao2_container_alloc_hash.

Referenced by action_coreshowchannelmap(), and ast_dns_get_nameservers().

201 {
202  return ao2_container_alloc_hash(opts, 0, buckets, str_hash, str_sort, str_cmp);
203 }
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
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 221 of file strings.c.

References OBJ_NODATA, OBJ_SEARCH_KEY, and OBJ_UNLINK.

Referenced by endpoint_cache_clear(), and test_cel_peer_strings_match().

222 {
223  ao2_find(str_container, remove, OBJ_SEARCH_KEY | OBJ_NODATA | OBJ_UNLINK);
224 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
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
Return values
trueif valid strings and equal.
falseotherwise.

Definition at line 238 of file strings.c.

239 {
240  if (!str1 || !str2) {
241  return 0;
242  }
243 
244  return str1 == str2 || !strcmp(str1, str2);
245 }
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 247 of file strings.c.

References ast_str_append(), ast_str_buffer(), ast_str_set(), and ast_strdupa.

Referenced by ast_variables_match().

248 {
249  char *internal_op = (char *)op;
250  char *internal_right = (char *)right;
251  double left_num;
252  double right_num;
253  int scan_numeric = 0;
254 
255  if (!(left && right)) {
256  return 0;
257  }
258 
259  if (ast_strlen_zero(op)) {
260  if (ast_strlen_zero(left) && ast_strlen_zero(right)) {
261  return 1;
262  }
263 
264  if (strlen(right) >= 2 && right[0] == '/' && right[strlen(right) - 1] == '/') {
265  internal_op = "regex";
266  internal_right = ast_strdupa(right);
267  /* strip the leading and trailing '/' */
268  internal_right++;
269  internal_right[strlen(internal_right) - 1] = '\0';
270  goto regex;
271  } else {
272  internal_op = "=";
273  goto equals;
274  }
275  }
276 
277  if (!strcasecmp(op, "like")) {
278  char *tok;
279  struct ast_str *buffer = ast_str_alloca(128);
280 
281  if (!strchr(right, '%')) {
282  return !strcmp(left, right);
283  } else {
284  internal_op = "regex";
285  internal_right = ast_strdupa(right);
286  tok = strsep(&internal_right, "%");
287  ast_str_set(&buffer, 0, "^%s", tok);
288 
289  while ((tok = strsep(&internal_right, "%"))) {
290  ast_str_append(&buffer, 0, ".*%s", tok);
291  }
292  ast_str_append(&buffer, 0, "%s", "$");
293 
294  internal_right = ast_str_buffer(buffer);
295  /* fall through to regex */
296  }
297  }
298 
299 regex:
300  if (!strcasecmp(internal_op, "regex")) {
301  regex_t expression;
302  int rc;
303 
304  if (regcomp(&expression, internal_right, REG_EXTENDED | REG_NOSUB)) {
305  return 0;
306  }
307 
308  rc = regexec(&expression, left, 0, NULL, 0);
309  regfree(&expression);
310  return !rc;
311  }
312 
313 equals:
314  scan_numeric = (sscanf(left, "%lf", &left_num) > 0 && sscanf(internal_right, "%lf", &right_num) > 0);
315 
316  if (internal_op[0] == '=') {
317  if (ast_strlen_zero(left) && ast_strlen_zero(internal_right)) {
318  return 1;
319  }
320 
321  if (scan_numeric) {
322  return (left_num == right_num);
323  } else {
324  return (!strcmp(left, internal_right));
325  }
326  }
327 
328  if (internal_op[0] == '!' && internal_op[1] == '=') {
329  if (scan_numeric) {
330  return (left_num != right_num);
331  } else {
332  return !!strcmp(left, internal_right);
333  }
334  }
335 
336  if (internal_op[0] == '<') {
337  if (scan_numeric) {
338  if (internal_op[1] == '=') {
339  return (left_num <= right_num);
340  } else {
341  return (left_num < right_num);
342  }
343  } else {
344  if (internal_op[1] == '=') {
345  return strcmp(left, internal_right) <= 0;
346  } else {
347  return strcmp(left, internal_right) < 0;
348  }
349  }
350  }
351 
352  if (internal_op[0] == '>') {
353  if (scan_numeric) {
354  if (internal_op[1] == '=') {
355  return (left_num >= right_num);
356  } else {
357  return (left_num > right_num);
358  }
359  } else {
360  if (internal_op[1] == '=') {
361  return strcmp(left, internal_right) >= 0;
362  } else {
363  return strcmp(left, internal_right) > 0;
364  }
365  }
366  }
367 
368  return 0;
369 }
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
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:1139
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:1113
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
Support for dynamic strings.
Definition: strings.h:623
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 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 392 of file strings.c.

References ast_strdup, ast_strdupa, ast_strip(), AST_VECTOR_APPEND, AST_VECTOR_GET_CMP, AST_VECTOR_STRING_SPLIT_ALLOW_EMPTY, and AST_VECTOR_STRING_SPLIT_NO_TRIM.

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