Asterisk - The Open Source Telephony Project GIT-master-a358458
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
247int ast_strings_match(const char *left, const char *op, const char *right)
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
299regex:
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
313equals:
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}
370
371char *ast_read_line_from_buffer(char **buffer)
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}
391
393 const char *input, const char *delim, int flags,
394 int (*excludes_cmp)(const char *s1, const char *s2))
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);
403
404 if (ast_strlen_zero(input)) {
405 return 0;
406 }
407
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}
432
433int ast_in_delimited_string(const char *needle, const char *haystack, char delim)
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}
456
if(!yyg->yy_init)
Definition: ast_expr2f.c:854
static int input(yyscan_t yyscanner)
Definition: ast_expr2f.c:1570
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
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)
char * strsep(char **str, const char *delims)
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:2463
#define LOG_VERBOSE
#define remove
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
int ast_strings_match(const char *left, const char *op, const char *right)
Compares 2 strings using realtime-style operators.
Definition: strings.c:247
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:433
char * ast_read_line_from_buffer(char **buffer)
Read lines from a string buffer.
Definition: strings.c:371
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:392
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.
@ AST_DYNSTR_BUILD_FAILED
Definition: strings.h:943
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
#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