Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
strings.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2008, Digium, Inc.
5 *
6 * Tilghman Lesher <tlesher@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15* the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief String manipulation API
22 *
23 * \author Tilghman Lesher <tilghman@digium.com>
24 */
25
26/*** MAKEOPTS
27<category name="MENUSELECT_CFLAGS" displayname="Compiler Flags" positive_output="yes">
28 <member name="DEBUG_OPAQUE" displayname="Change ast_str internals to detect improper usage" touch_on_change="include/asterisk/strings.h">
29 <defaultenabled>yes</defaultenabled>
30 </member>
31</category>
32 ***/
33
34/*** MODULEINFO
35 <support_level>core</support_level>
36 ***/
37
38#include "asterisk.h"
39
40#include <regex.h>
41#include "asterisk/strings.h"
42#include "asterisk/pbx.h"
43#include "asterisk/vector.h"
44
45/*!
46 * core handler for dynamic strings.
47 * This is not meant to be called directly, but rather through the
48 * various wrapper macros
49 * ast_str_set(...)
50 * ast_str_append(...)
51 * ast_str_set_va(...)
52 * ast_str_append_va(...)
53 */
54
55int __ast_str_helper(struct ast_str **buf, ssize_t max_len,
56 int append, const char *fmt, va_list ap,
57 const char *file, int lineno, const char *function)
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}
128
129char *__ast_str_helper2(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc, int append, int escapecommas)
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}
172
173static int str_hash(const void *obj, const int flags)
174{
175 return ast_str_hash(obj);
176}
177
178static int str_sort(const void *lhs, const void *rhs, int flags)
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}
186
187static int str_cmp(void *lhs, void *rhs, int flags)
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}
199
201{
202 return ao2_container_alloc_hash(opts, 0, buckets, str_hash, str_sort, str_cmp);
203}
204
205int ast_str_container_add(struct ao2_container *str_container, const char *add)
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}
220
221void ast_str_container_remove(struct ao2_container *str_container, const char *remove)
222{
224}
225
226char *ast_generate_random_string(char *buf, size_t size)
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}
237
238int ast_strings_equal(const char *str1, const char *str2)
239{
240 if (!str1 || !str2) {
241 return 0;
242 }
243
244 return str1 == str2 || !strcmp(str1, str2);
245}
246
247static int parse_double(const char *input, double *result)
248{
249 char *endptr;
250
251 errno = 0;
252 *result = strtod(input, &endptr);
253 if (*endptr || errno == ERANGE) {
254 return 0;
255 }
256
257 return 1;
258}
259
260int ast_strings_match(const char *left, const char *op, const char *right)
261{
262 char *internal_op = (char *)op;
263 char *internal_right = (char *)right;
264 double left_num;
265 double right_num;
266 int scan_numeric = 0;
267
268 if (!(left && right)) {
269 return 0;
270 }
271
272 if (ast_strlen_zero(op)) {
273 if (ast_strlen_zero(left) && ast_strlen_zero(right)) {
274 return 1;
275 }
276
277 if (strlen(right) >= 2 && right[0] == '/' && right[strlen(right) - 1] == '/') {
278 internal_op = "regex";
279 internal_right = ast_strdupa(right);
280 /* strip the leading and trailing '/' */
281 internal_right++;
282 internal_right[strlen(internal_right) - 1] = '\0';
283 goto regex;
284 } else {
285 internal_op = "=";
286 goto equals;
287 }
288 }
289
290 if (!strcasecmp(op, "like")) {
291 char *tok;
292 struct ast_str *buffer = ast_str_alloca(128);
293
294 if (!strchr(right, '%')) {
295 return !strcmp(left, right);
296 } else {
297 internal_op = "regex";
298 internal_right = ast_strdupa(right);
299 tok = strsep(&internal_right, "%");
300 ast_str_set(&buffer, 0, "^%s", tok);
301
302 while ((tok = strsep(&internal_right, "%"))) {
303 ast_str_append(&buffer, 0, ".*%s", tok);
304 }
305 ast_str_append(&buffer, 0, "%s", "$");
306
307 internal_right = ast_str_buffer(buffer);
308 /* fall through to regex */
309 }
310 }
311
312regex:
313 if (!strcasecmp(internal_op, "regex")) {
314 regex_t expression;
315 int rc;
316
317 if (regcomp(&expression, internal_right, REG_EXTENDED | REG_NOSUB)) {
318 return 0;
319 }
320
321 rc = regexec(&expression, left, 0, NULL, 0);
322 regfree(&expression);
323 return !rc;
324 }
325
326equals:
327 scan_numeric = parse_double(left, &left_num)
328 && parse_double(internal_right, &right_num);
329
330 if (internal_op[0] == '=') {
331 if (ast_strlen_zero(left) && ast_strlen_zero(internal_right)) {
332 return 1;
333 }
334
335 if (scan_numeric) {
336 return (left_num == right_num);
337 } else {
338 return (!strcmp(left, internal_right));
339 }
340 }
341
342 if (internal_op[0] == '!' && internal_op[1] == '=') {
343 if (scan_numeric) {
344 return (left_num != right_num);
345 } else {
346 return !!strcmp(left, internal_right);
347 }
348 }
349
350 if (internal_op[0] == '<') {
351 if (scan_numeric) {
352 if (internal_op[1] == '=') {
353 return (left_num <= right_num);
354 } else {
355 return (left_num < right_num);
356 }
357 } else {
358 if (internal_op[1] == '=') {
359 return strcmp(left, internal_right) <= 0;
360 } else {
361 return strcmp(left, internal_right) < 0;
362 }
363 }
364 }
365
366 if (internal_op[0] == '>') {
367 if (scan_numeric) {
368 if (internal_op[1] == '=') {
369 return (left_num >= right_num);
370 } else {
371 return (left_num > right_num);
372 }
373 } else {
374 if (internal_op[1] == '=') {
375 return strcmp(left, internal_right) >= 0;
376 } else {
377 return strcmp(left, internal_right) > 0;
378 }
379 }
380 }
381
382 return 0;
383}
384
385char *ast_read_line_from_buffer(char **buffer)
386{
387 char *start = *buffer;
388
389 if (!buffer || !*buffer || *(*buffer) == '\0') {
390 return NULL;
391 }
392
393 while (*(*buffer) && *(*buffer) != '\n' ) {
394 (*buffer)++;
395 }
396
397 *(*buffer) = '\0';
398 if (*(*buffer - 1) == '\r') {
399 *(*buffer - 1) = '\0';
400 }
401 (*buffer)++;
402
403 return start;
404}
405
407 const char *input, const char *delim, int flags,
408 int (*excludes_cmp)(const char *s1, const char *s2))
409{
410 char *buf;
411 char *cur;
412 int no_trim = flags & AST_VECTOR_STRING_SPLIT_NO_TRIM;
413 int allow_empty = flags & AST_VECTOR_STRING_SPLIT_ALLOW_EMPTY;
414
415 ast_assert(dest != NULL);
417
418 if (ast_strlen_zero(input)) {
419 return 0;
420 }
421
423 while ((cur = strsep(&buf, delim))) {
424 if (!no_trim) {
425 cur = ast_strip(cur);
426 }
427
428 if (!allow_empty && ast_strlen_zero(cur)) {
429 continue;
430 }
431
432 if (excludes_cmp && AST_VECTOR_GET_CMP(dest, cur, !excludes_cmp)) {
433 continue;
434 }
435
436 cur = ast_strdup(cur);
437 if (!cur || AST_VECTOR_APPEND(dest, cur)) {
438 ast_free(cur);
439
440 return -1;
441 }
442 }
443
444 return 0;
445}
446
447int ast_in_delimited_string(const char *needle, const char *haystack, char delim)
448{
449 const char *end;
450 unsigned long needle_size;
451
452 ast_assert(haystack != NULL);
453
454 if (!needle) {
455 return 0;
456 }
457
458 needle_size = strlen(needle);
459 haystack = ast_skip_blanks(haystack);
460
461 while ((end = strchr(haystack, delim))) {
462 if (needle_size == end - haystack && !strncmp(haystack, needle, needle_size)) {
463 return 1;
464 }
465 haystack = ast_skip_blanks(end + 1);
466 }
467
468 return strcmp(haystack, needle) ? 0 : -1;
469}
470
if(!yyg->yy_init)
Definition: ast_expr2f.c:854
static int input(yyscan_t yyscanner)
Definition: ast_expr2f.c:1570
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#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
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ CMP_MATCH
Definition: astobj2.h:1027
ao2_alloc_opts
Options available when allocating an ao2 object.
Definition: astobj2.h:361
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072
@ OBJ_UNLINK
Definition: astobj2.h:1039
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#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
static PGresult * result
Definition: cel_pgsql.c:84
char * end
Definition: eagi_proxy.c:73
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
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:2450
#define LOG_VERBOSE
#define remove
int errno
Core PBX routines and definitions.
#define NULL
Definition: resample.c:96
int ast_strings_equal(const char *str1, const char *str2)
Compare strings for equality checking for NULL.
Definition: strings.c:238
static int str_sort(const void *lhs, const void *rhs, int flags)
Definition: strings.c:178
static int parse_double(const char *input, double *result)
Definition: strings.c:247
int ast_strings_match(const char *left, const char *op, const char *right)
Compares 2 strings using realtime-style operators.
Definition: strings.c:260
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'.
Definition: strings.c:447
char * ast_read_line_from_buffer(char **buffer)
Read lines from a string buffer.
Definition: strings.c:385
static int str_cmp(void *lhs, void *rhs, int flags)
Definition: strings.c:187
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.
Definition: strings.c:55
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.
Definition: strings.c:406
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.
Definition: strings.c:221
char * ast_generate_random_string(char *buf, size_t size)
Create a pseudo-random string of a fixed length.
Definition: strings.c:226
struct ao2_container * ast_str_container_alloc_options(enum ao2_alloc_opts opts, int buckets)
Allocates a hash container for bare strings.
Definition: strings.c:200
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.
Definition: strings.c:205
static int str_hash(const void *obj, const int flags)
Definition: strings.c:173
char * __ast_str_helper2(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc, int append, int escapecommas)
Definition: strings.c:129
String manipulation functions.
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
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259
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
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
@ AST_DYNSTR_BUILD_FAILED
Definition: strings.h:943
#define ast_str_alloca(init_len)
Definition: strings.h:848
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_str_make_space(buf, new_len)
Definition: strings.h:828
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:161
Generic container type.
Support for dynamic strings.
Definition: strings.h:623
String vector definitions.
Definition: vector.h:55
#define ast_assert(a)
Definition: utils.h:739
long int ast_random(void)
Definition: utils.c:2312
Vector container support.
#define AST_VECTOR_GET_CMP(vec, value, cmp)
Get an element from a vector that matches the given comparison.
Definition: vector.h:731
@ AST_VECTOR_STRING_SPLIT_NO_TRIM
Definition: vector.h:61
@ AST_VECTOR_STRING_SPLIT_ALLOW_EMPTY
Definition: vector.h:63
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256