update thread creation code a bit
[asterisk-bristuff.git] / main / utils.c
blob3f44fe777fde7fb6ec5ff296080c2cf00722c9be
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * See http://www.asterisk.org for more information about
7 * the Asterisk project. Please do not directly contact
8 * any of the maintainers of this project for assistance;
9 * the project provides a web site, mailing lists and IRC
10 * channels for your use.
12 * This program is free software, distributed under the terms of
13 * the GNU General Public License Version 2. See the LICENSE file
14 * at the top of the source tree.
17 /*! \file
19 * \brief Utility functions
21 * \note These are important for portability and security,
22 * so please use them in favour of other routines.
23 * Please consult the CODING GUIDELINES for more information.
26 #include "asterisk.h"
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30 #include <ctype.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
42 #define AST_API_MODULE /* ensure that inlinable API functions will be built in lock.h if required */
43 #include "asterisk/lock.h"
44 #include "asterisk/io.h"
45 #include "asterisk/logger.h"
46 #include "asterisk/md5.h"
47 #include "asterisk/sha1.h"
48 #include "asterisk/options.h"
50 #define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
51 #include "asterisk/strings.h"
53 #define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
54 #include "asterisk/time.h"
56 #define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
57 #include "asterisk/stringfields.h"
59 #define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
60 #include "asterisk/utils.h"
62 #define AST_API_MODULE
63 #include "asterisk/threadstorage.h"
65 static char base64[64];
66 static char b2a[256];
68 AST_THREADSTORAGE(inet_ntoa_buf, inet_ntoa_buf_init);
70 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) || defined(__CYGWIN__)
72 #define ERANGE 34 /*!< duh? ERANGE value copied from web... */
73 #undef gethostbyname
75 AST_MUTEX_DEFINE_STATIC(__mutex);
77 /*! \brief Reentrant replacement for gethostbyname for BSD-based systems.
78 \note This
79 routine is derived from code originally written and placed in the public
80 domain by Enzo Michelangeli <em@em.no-ip.com> */
82 static int gethostbyname_r (const char *name, struct hostent *ret, char *buf,
83 size_t buflen, struct hostent **result,
84 int *h_errnop)
86 int hsave;
87 struct hostent *ph;
88 ast_mutex_lock(&__mutex); /* begin critical area */
89 hsave = h_errno;
91 ph = gethostbyname(name);
92 *h_errnop = h_errno; /* copy h_errno to *h_herrnop */
93 if (ph == NULL) {
94 *result = NULL;
95 } else {
96 char **p, **q;
97 char *pbuf;
98 int nbytes=0;
99 int naddr=0, naliases=0;
100 /* determine if we have enough space in buf */
102 /* count how many addresses */
103 for (p = ph->h_addr_list; *p != 0; p++) {
104 nbytes += ph->h_length; /* addresses */
105 nbytes += sizeof(*p); /* pointers */
106 naddr++;
108 nbytes += sizeof(*p); /* one more for the terminating NULL */
110 /* count how many aliases, and total length of strings */
111 for (p = ph->h_aliases; *p != 0; p++) {
112 nbytes += (strlen(*p)+1); /* aliases */
113 nbytes += sizeof(*p); /* pointers */
114 naliases++;
116 nbytes += sizeof(*p); /* one more for the terminating NULL */
118 /* here nbytes is the number of bytes required in buffer */
119 /* as a terminator must be there, the minimum value is ph->h_length */
120 if (nbytes > buflen) {
121 *result = NULL;
122 ast_mutex_unlock(&__mutex); /* end critical area */
123 return ERANGE; /* not enough space in buf!! */
126 /* There is enough space. Now we need to do a deep copy! */
127 /* Allocation in buffer:
128 from [0] to [(naddr-1) * sizeof(*p)]:
129 pointers to addresses
130 at [naddr * sizeof(*p)]:
131 NULL
132 from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] :
133 pointers to aliases
134 at [(naddr+naliases+1) * sizeof(*p)]:
135 NULL
136 then naddr addresses (fixed length), and naliases aliases (asciiz).
139 *ret = *ph; /* copy whole structure (not its address!) */
141 /* copy addresses */
142 q = (char **)buf; /* pointer to pointers area (type: char **) */
143 ret->h_addr_list = q; /* update pointer to address list */
144 pbuf = buf + ((naddr + naliases + 2) * sizeof(*p)); /* skip that area */
145 for (p = ph->h_addr_list; *p != 0; p++) {
146 memcpy(pbuf, *p, ph->h_length); /* copy address bytes */
147 *q++ = pbuf; /* the pointer is the one inside buf... */
148 pbuf += ph->h_length; /* advance pbuf */
150 *q++ = NULL; /* address list terminator */
152 /* copy aliases */
153 ret->h_aliases = q; /* update pointer to aliases list */
154 for (p = ph->h_aliases; *p != 0; p++) {
155 strcpy(pbuf, *p); /* copy alias strings */
156 *q++ = pbuf; /* the pointer is the one inside buf... */
157 pbuf += strlen(*p); /* advance pbuf */
158 *pbuf++ = 0; /* string terminator */
160 *q++ = NULL; /* terminator */
162 strcpy(pbuf, ph->h_name); /* copy alias strings */
163 ret->h_name = pbuf;
164 pbuf += strlen(ph->h_name); /* advance pbuf */
165 *pbuf++ = 0; /* string terminator */
167 *result = ret; /* and let *result point to structure */
170 h_errno = hsave; /* restore h_errno */
171 ast_mutex_unlock(&__mutex); /* end critical area */
173 return (*result == NULL); /* return 0 on success, non-zero on error */
177 #endif
179 /*! \brief Re-entrant (thread safe) version of gethostbyname that replaces the
180 standard gethostbyname (which is not thread safe)
182 struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp)
184 int res;
185 int herrno;
186 int dots=0;
187 const char *s;
188 struct hostent *result = NULL;
189 /* Although it is perfectly legitimate to lookup a pure integer, for
190 the sake of the sanity of people who like to name their peers as
191 integers, we break with tradition and refuse to look up a
192 pure integer */
193 s = host;
194 res = 0;
195 while(s && *s) {
196 if (*s == '.')
197 dots++;
198 else if (!isdigit(*s))
199 break;
200 s++;
202 if (!s || !*s) {
203 /* Forge a reply for IP's to avoid octal IP's being interpreted as octal */
204 if (dots != 3)
205 return NULL;
206 memset(hp, 0, sizeof(struct ast_hostent));
207 hp->hp.h_addr_list = (void *) hp->buf;
208 hp->hp.h_addr = hp->buf + sizeof(void *);
209 if (inet_pton(AF_INET, host, hp->hp.h_addr) > 0)
210 return &hp->hp;
211 return NULL;
214 #ifdef SOLARIS
215 result = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &herrno);
217 if (!result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
218 return NULL;
219 #else
220 res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno);
222 if (res || !result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
223 return NULL;
224 #endif
225 return &hp->hp;
230 AST_MUTEX_DEFINE_STATIC(test_lock);
231 AST_MUTEX_DEFINE_STATIC(test_lock2);
232 static pthread_t test_thread;
233 static int lock_count = 0;
234 static int test_errors = 0;
236 /*! \brief This is a regression test for recursive mutexes.
237 test_for_thread_safety() will return 0 if recursive mutex locks are
238 working properly, and non-zero if they are not working properly. */
239 static void *test_thread_body(void *data)
241 ast_mutex_lock(&test_lock);
242 lock_count += 10;
243 if (lock_count != 10)
244 test_errors++;
245 ast_mutex_lock(&test_lock);
246 lock_count += 10;
247 if (lock_count != 20)
248 test_errors++;
249 ast_mutex_lock(&test_lock2);
250 ast_mutex_unlock(&test_lock);
251 lock_count -= 10;
252 if (lock_count != 10)
253 test_errors++;
254 ast_mutex_unlock(&test_lock);
255 lock_count -= 10;
256 ast_mutex_unlock(&test_lock2);
257 if (lock_count != 0)
258 test_errors++;
259 return NULL;
262 int test_for_thread_safety(void)
264 ast_mutex_lock(&test_lock2);
265 ast_mutex_lock(&test_lock);
266 lock_count += 1;
267 ast_mutex_lock(&test_lock);
268 lock_count += 1;
269 ast_pthread_create(&test_thread, NULL, test_thread_body, NULL);
270 usleep(100);
271 if (lock_count != 2)
272 test_errors++;
273 ast_mutex_unlock(&test_lock);
274 lock_count -= 1;
275 usleep(100);
276 if (lock_count != 1)
277 test_errors++;
278 ast_mutex_unlock(&test_lock);
279 lock_count -= 1;
280 if (lock_count != 0)
281 test_errors++;
282 ast_mutex_unlock(&test_lock2);
283 usleep(100);
284 if (lock_count != 0)
285 test_errors++;
286 pthread_join(test_thread, NULL);
287 return(test_errors); /* return 0 on success. */
290 /*! \brief Produce 32 char MD5 hash of value. */
291 void ast_md5_hash(char *output, char *input)
293 struct MD5Context md5;
294 unsigned char digest[16];
295 char *ptr;
296 int x;
298 MD5Init(&md5);
299 MD5Update(&md5, (unsigned char *)input, strlen(input));
300 MD5Final(digest, &md5);
301 ptr = output;
302 for (x = 0; x < 16; x++)
303 ptr += sprintf(ptr, "%2.2x", digest[x]);
306 /*! \brief Produce 40 char SHA1 hash of value. */
307 void ast_sha1_hash(char *output, char *input)
309 struct SHA1Context sha;
310 char *ptr;
311 int x;
312 uint8_t Message_Digest[20];
314 SHA1Reset(&sha);
316 SHA1Input(&sha, (const unsigned char *) input, strlen(input));
318 SHA1Result(&sha, Message_Digest);
319 ptr = output;
320 for (x = 0; x < 20; x++)
321 ptr += sprintf(ptr, "%2.2x", Message_Digest[x]);
324 /*! \brief decode BASE64 encoded text */
325 int ast_base64decode(unsigned char *dst, const char *src, int max)
327 int cnt = 0;
328 unsigned int byte = 0;
329 unsigned int bits = 0;
330 int incnt = 0;
331 while(*src && (cnt < max)) {
332 /* Shift in 6 bits of input */
333 byte <<= 6;
334 byte |= (b2a[(int)(*src)]) & 0x3f;
335 bits += 6;
336 src++;
337 incnt++;
338 /* If we have at least 8 bits left over, take that character
339 off the top */
340 if (bits >= 8) {
341 bits -= 8;
342 *dst = (byte >> bits) & 0xff;
343 dst++;
344 cnt++;
347 /* Dont worry about left over bits, they're extra anyway */
348 return cnt;
351 /*! \brief encode text to BASE64 coding */
352 int ast_base64encode_full(char *dst, const unsigned char *src, int srclen, int max, int linebreaks)
354 int cnt = 0;
355 int col = 0;
356 unsigned int byte = 0;
357 int bits = 0;
358 int cntin = 0;
359 /* Reserve space for null byte at end of string */
360 max--;
361 while ((cntin < srclen) && (cnt < max)) {
362 byte <<= 8;
363 byte |= *(src++);
364 bits += 8;
365 cntin++;
366 if ((bits == 24) && (cnt + 4 <= max)) {
367 *dst++ = base64[(byte >> 18) & 0x3f];
368 *dst++ = base64[(byte >> 12) & 0x3f];
369 *dst++ = base64[(byte >> 6) & 0x3f];
370 *dst++ = base64[byte & 0x3f];
371 cnt += 4;
372 col += 4;
373 bits = 0;
374 byte = 0;
376 if (linebreaks && (cnt < max) && (col == 64)) {
377 *dst++ = '\n';
378 cnt++;
379 col = 0;
382 if (bits && (cnt + 4 <= max)) {
383 /* Add one last character for the remaining bits,
384 padding the rest with 0 */
385 byte <<= 24 - bits;
386 *dst++ = base64[(byte >> 18) & 0x3f];
387 *dst++ = base64[(byte >> 12) & 0x3f];
388 if (bits == 16)
389 *dst++ = base64[(byte >> 6) & 0x3f];
390 else
391 *dst++ = '=';
392 *dst++ = '=';
393 cnt += 4;
395 if (linebreaks && (cnt < max)) {
396 *dst++ = '\n';
397 cnt++;
399 *dst = '\0';
400 return cnt;
403 int ast_base64encode(char *dst, const unsigned char *src, int srclen, int max)
405 return ast_base64encode_full(dst, src, srclen, max, 0);
408 static void base64_init(void)
410 int x;
411 memset(b2a, -1, sizeof(b2a));
412 /* Initialize base-64 Conversion table */
413 for (x = 0; x < 26; x++) {
414 /* A-Z */
415 base64[x] = 'A' + x;
416 b2a['A' + x] = x;
417 /* a-z */
418 base64[x + 26] = 'a' + x;
419 b2a['a' + x] = x + 26;
420 /* 0-9 */
421 if (x < 10) {
422 base64[x + 52] = '0' + x;
423 b2a['0' + x] = x + 52;
426 base64[62] = '+';
427 base64[63] = '/';
428 b2a[(int)'+'] = 62;
429 b2a[(int)'/'] = 63;
432 /*! \brief ast_uri_encode: Turn text string to URI-encoded %XX version
433 \note At this point, we're converting from ISO-8859-x (8-bit), not UTF8
434 as in the SIP protocol spec
435 If doreserved == 1 we will convert reserved characters also.
436 RFC 2396, section 2.4
437 outbuf needs to have more memory allocated than the instring
438 to have room for the expansion. Every char that is converted
439 is replaced by three ASCII characters.
441 Note: The doreserved option is needed for replaces header in
442 SIP transfers.
444 char *ast_uri_encode(const char *string, char *outbuf, int buflen, int doreserved)
446 char *reserved = ";/?:@&=+$, "; /* Reserved chars */
448 const char *ptr = string; /* Start with the string */
449 char *out = NULL;
450 char *buf = NULL;
452 strncpy(outbuf, string, buflen);
454 /* If there's no characters to convert, just go through and don't do anything */
455 while (*ptr) {
456 if (((unsigned char) *ptr) > 127 || (doreserved && strchr(reserved, *ptr)) ) {
457 /* Oops, we need to start working here */
458 if (!buf) {
459 buf = outbuf;
460 out = buf + (ptr - string) ; /* Set output ptr */
462 out += sprintf(out, "%%%02x", (unsigned char) *ptr);
463 } else if (buf) {
464 *out = *ptr; /* Continue copying the string */
465 out++;
467 ptr++;
469 if (buf)
470 *out = '\0';
471 return outbuf;
474 /*! \brief ast_uri_decode: Decode SIP URI, URN, URL (overwrite the string) */
475 void ast_uri_decode(char *s)
477 char *o;
478 unsigned int tmp;
480 for (o = s; *s; s++, o++) {
481 if (*s == '%' && strlen(s) > 2 && sscanf(s + 1, "%2x", &tmp) == 1) {
482 /* have '%', two chars and correct parsing */
483 *o = tmp;
484 s += 2; /* Will be incremented once more when we break out */
485 } else /* all other cases, just copy */
486 *o = *s;
488 *o = '\0';
491 /*! \brief ast_inet_ntoa: Recursive thread safe replacement of inet_ntoa */
492 const char *ast_inet_ntoa(struct in_addr ia)
494 char *buf;
496 if (!(buf = ast_threadstorage_get(&inet_ntoa_buf, INET_ADDRSTRLEN)))
497 return "";
499 return inet_ntop(AF_INET, &ia, buf, INET_ADDRSTRLEN);
502 int ast_utils_init(void)
504 base64_init();
505 return 0;
508 #ifndef __linux__
509 #undef pthread_create /* For ast_pthread_create function only */
510 #endif /* !__linux__ */
513 * support for 'show threads'. The start routine is wrapped by
514 * dummy_start(), so that ast_register_thread() and
515 * ast_unregister_thread() know the thread identifier.
517 struct thr_arg {
518 void *(*start_routine)(void *);
519 void *data;
520 char *name;
524 * on OS/X, pthread_cleanup_push() and pthread_cleanup_pop()
525 * are odd macros which start and end a block, so they _must_ be
526 * used in pairs (the latter with a '1' argument to call the
527 * handler on exit.
528 * On BSD we don't need this, but we keep it for compatibility.
530 static void *dummy_start(void *data)
532 void *ret;
533 struct thr_arg a = *((struct thr_arg *) data); /* make a local copy */
535 /* note that even though data->name is a pointer to allocated memory,
536 we are not freeing it here because ast_register_thread is going to
537 keep a copy of the pointer and then ast_unregister_thread will
538 free the memory
540 free(data);
541 ast_register_thread(a.name);
542 pthread_cleanup_push(ast_unregister_thread, (void *) pthread_self());
543 ret = a.start_routine(a.data);
544 pthread_cleanup_pop(1);
546 return ret;
549 int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *),
550 void *data, size_t stacksize, const char *file, const char *caller,
551 int line, const char *start_fn)
553 struct thr_arg *a;
555 if (!attr) {
556 attr = alloca(sizeof(*attr));
557 pthread_attr_init(attr);
560 #ifdef __linux__
561 /* On Linux, pthread_attr_init() defaults to PTHREAD_EXPLICIT_SCHED,
562 which is kind of useless. Change this here to
563 PTHREAD_INHERIT_SCHED; that way the -p option to set realtime
564 priority will propagate down to new threads by default.
565 This does mean that callers cannot set a different priority using
566 PTHREAD_EXPLICIT_SCHED in the attr argument; instead they must set
567 the priority afterwards with pthread_setschedparam(). */
568 if ((errno = pthread_attr_setinheritsched(attr, PTHREAD_INHERIT_SCHED)))
569 ast_log(LOG_WARNING, "pthread_attr_setinheritsched: %s\n", strerror(errno));
570 #endif
572 if (!stacksize)
573 stacksize = AST_STACKSIZE;
575 if ((errno = pthread_attr_setstacksize(attr, stacksize ? stacksize : AST_STACKSIZE)))
576 ast_log(LOG_WARNING, "pthread_attr_setstacksize: %s\n", strerror(errno));
578 if ((a = ast_malloc(sizeof(*a)))) {
579 a->start_routine = start_routine;
580 a->data = data;
581 start_routine = dummy_start;
582 asprintf(&a->name, "%-20s started at [%5d] %s %s()",
583 start_fn, line, file, caller);
584 data = a;
587 return pthread_create(thread, attr, start_routine, data); /* We're in ast_pthread_create, so it's okay */
590 int ast_wait_for_input(int fd, int ms)
592 struct pollfd pfd[1];
593 memset(pfd, 0, sizeof(pfd));
594 pfd[0].fd = fd;
595 pfd[0].events = POLLIN|POLLPRI;
596 return poll(pfd, 1, ms);
599 int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
601 /* Try to write string, but wait no more than ms milliseconds
602 before timing out */
603 int res = 0;
604 struct pollfd fds[1];
605 while (len) {
606 res = write(fd, s, len);
607 if ((res < 0) && (errno != EAGAIN)) {
608 return -1;
610 if (res < 0)
611 res = 0;
612 len -= res;
613 s += res;
614 res = 0;
615 if (len) {
616 fds[0].fd = fd;
617 fds[0].events = POLLOUT;
618 /* Wait until writable again */
619 res = poll(fds, 1, timeoutms);
620 if (res < 1)
621 return -1;
624 return res;
627 char *ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
629 char *e;
630 char *q;
632 s = ast_strip(s);
633 if ((q = strchr(beg_quotes, *s))) {
634 e = s + strlen(s) - 1;
635 if (*e == *(end_quotes + (q - beg_quotes))) {
636 s++;
637 *e = '\0';
641 return s;
644 int ast_build_string_va(char **buffer, size_t *space, const char *fmt, va_list ap)
646 int result;
648 if (!buffer || !*buffer || !space || !*space)
649 return -1;
651 result = vsnprintf(*buffer, *space, fmt, ap);
653 if (result < 0)
654 return -1;
655 else if (result > *space)
656 result = *space;
658 *buffer += result;
659 *space -= result;
660 return 0;
663 int ast_build_string(char **buffer, size_t *space, const char *fmt, ...)
665 va_list ap;
666 int result;
668 va_start(ap, fmt);
669 result = ast_build_string_va(buffer, space, fmt, ap);
670 va_end(ap);
672 return result;
675 int ast_true(const char *s)
677 if (ast_strlen_zero(s))
678 return 0;
680 /* Determine if this is a true value */
681 if (!strcasecmp(s, "yes") ||
682 !strcasecmp(s, "true") ||
683 !strcasecmp(s, "y") ||
684 !strcasecmp(s, "t") ||
685 !strcasecmp(s, "1") ||
686 !strcasecmp(s, "on"))
687 return -1;
689 return 0;
692 int ast_false(const char *s)
694 if (ast_strlen_zero(s))
695 return 0;
697 /* Determine if this is a false value */
698 if (!strcasecmp(s, "no") ||
699 !strcasecmp(s, "false") ||
700 !strcasecmp(s, "n") ||
701 !strcasecmp(s, "f") ||
702 !strcasecmp(s, "0") ||
703 !strcasecmp(s, "off"))
704 return -1;
706 return 0;
709 #define ONE_MILLION 1000000
711 * put timeval in a valid range. usec is 0..999999
712 * negative values are not allowed and truncated.
714 static struct timeval tvfix(struct timeval a)
716 if (a.tv_usec >= ONE_MILLION) {
717 ast_log(LOG_WARNING, "warning too large timestamp %ld.%ld\n",
718 a.tv_sec, (long int) a.tv_usec);
719 a.tv_sec += a.tv_usec / ONE_MILLION;
720 a.tv_usec %= ONE_MILLION;
721 } else if (a.tv_usec < 0) {
722 ast_log(LOG_WARNING, "warning negative timestamp %ld.%ld\n",
723 a.tv_sec, (long int) a.tv_usec);
724 a.tv_usec = 0;
726 return a;
729 struct timeval ast_tvadd(struct timeval a, struct timeval b)
731 /* consistency checks to guarantee usec in 0..999999 */
732 a = tvfix(a);
733 b = tvfix(b);
734 a.tv_sec += b.tv_sec;
735 a.tv_usec += b.tv_usec;
736 if (a.tv_usec >= ONE_MILLION) {
737 a.tv_sec++;
738 a.tv_usec -= ONE_MILLION;
740 return a;
743 struct timeval ast_tvsub(struct timeval a, struct timeval b)
745 /* consistency checks to guarantee usec in 0..999999 */
746 a = tvfix(a);
747 b = tvfix(b);
748 a.tv_sec -= b.tv_sec;
749 a.tv_usec -= b.tv_usec;
750 if (a.tv_usec < 0) {
751 a.tv_sec-- ;
752 a.tv_usec += ONE_MILLION;
754 return a;
756 #undef ONE_MILLION
758 /*! \brief glibc puts a lock inside random(3), so that the results are thread-safe.
759 * BSD libc (and others) do not. */
760 #ifndef linux
762 AST_MUTEX_DEFINE_STATIC(randomlock);
764 long int ast_random(void)
766 long int res;
767 ast_mutex_lock(&randomlock);
768 res = random();
769 ast_mutex_unlock(&randomlock);
770 return res;
772 #endif
774 char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
776 char *dataPut = start;
777 int inEscape = 0;
778 int inQuotes = 0;
780 for (; *start; start++) {
781 if (inEscape) {
782 *dataPut++ = *start; /* Always goes verbatim */
783 inEscape = 0;
784 } else {
785 if (*start == '\\') {
786 inEscape = 1; /* Do not copy \ into the data */
787 } else if (*start == '\'') {
788 inQuotes = 1 - inQuotes; /* Do not copy ' into the data */
789 } else {
790 /* Replace , with |, unless in quotes */
791 *dataPut++ = inQuotes ? *start : ((*start == find) ? replace_with : *start);
795 if (start != dataPut)
796 *dataPut = 0;
797 return dataPut;
800 void ast_join(char *s, size_t len, char * const w[])
802 int x, ofs = 0;
803 const char *src;
805 /* Join words into a string */
806 if (!s)
807 return;
808 for (x = 0; ofs < len && w[x]; x++) {
809 if (x > 0)
810 s[ofs++] = ' ';
811 for (src = w[x]; *src && ofs < len; src++)
812 s[ofs++] = *src;
814 if (ofs == len)
815 ofs--;
816 s[ofs] = '\0';
819 const char __ast_string_field_empty[] = "";
821 static int add_string_pool(struct ast_string_field_mgr *mgr, size_t size)
823 struct ast_string_field_pool *pool;
825 if (!(pool = ast_calloc(1, sizeof(*pool) + size)))
826 return -1;
828 pool->prev = mgr->pool;
829 mgr->pool = pool;
830 mgr->size = size;
831 mgr->space = size;
832 mgr->used = 0;
834 return 0;
837 int __ast_string_field_init(struct ast_string_field_mgr *mgr, size_t size,
838 ast_string_field *fields, int num_fields)
840 int index;
842 if (add_string_pool(mgr, size))
843 return -1;
845 for (index = 0; index < num_fields; index++)
846 fields[index] = __ast_string_field_empty;
848 return 0;
851 ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr, size_t needed,
852 ast_string_field *fields, int num_fields)
854 char *result = NULL;
856 if (__builtin_expect(needed > mgr->space, 0)) {
857 size_t new_size = mgr->size * 2;
859 while (new_size < needed)
860 new_size *= 2;
862 if (add_string_pool(mgr, new_size))
863 return NULL;
866 result = mgr->pool->base + mgr->used;
867 mgr->used += needed;
868 mgr->space -= needed;
869 return result;
872 void __ast_string_field_index_build(struct ast_string_field_mgr *mgr,
873 ast_string_field *fields, int num_fields,
874 int index, const char *format, ...)
876 size_t needed;
877 va_list ap1, ap2;
879 va_start(ap1, format);
880 va_start(ap2, format); /* va_copy does not exist on FreeBSD */
882 needed = vsnprintf(mgr->pool->base + mgr->used, mgr->space, format, ap1) + 1;
884 va_end(ap1);
886 if (needed > mgr->space) {
887 size_t new_size = mgr->size * 2;
889 while (new_size < needed)
890 new_size *= 2;
892 if (add_string_pool(mgr, new_size))
893 return;
895 vsprintf(mgr->pool->base + mgr->used, format, ap2);
898 fields[index] = mgr->pool->base + mgr->used;
899 mgr->used += needed;
900 mgr->space -= needed;
902 va_end(ap2);
905 AST_MUTEX_DEFINE_STATIC(fetchadd_m); /* used for all fetc&add ops */
907 int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
909 int ret;
910 ast_mutex_lock(&fetchadd_m);
911 ret = *p;
912 *p += v;
913 ast_mutex_unlock(&fetchadd_m);
914 return ret;
917 /*! \brief
918 * get values from config variables.
920 int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
922 long t;
923 int scanned;
925 if (dst == NULL)
926 return -1;
928 *dst = _default;
930 if (ast_strlen_zero(src))
931 return -1;
933 /* only integer at the moment, but one day we could accept more formats */
934 if (sscanf(src, "%ld%n", &t, &scanned) == 1) {
935 *dst = t;
936 if (consumed)
937 *consumed = scanned;
938 return 0;
939 } else
940 return -1;
943 int ast_dynamic_str_thread_build_va(struct ast_dynamic_str **buf, size_t max_len,
944 struct ast_threadstorage *ts, int append, const char *fmt, va_list ap)
946 int res;
947 int offset = (append && (*buf)->len) ? strlen((*buf)->str) : 0;
949 res = vsnprintf((*buf)->str + offset, (*buf)->len - offset, fmt, ap);
951 /* Check to see if there was not enough space in the string buffer to prepare
952 * the string. Also, if a maximum length is present, make sure the current
953 * length is less than the maximum before increasing the size. */
954 if ((res + offset + 1) > (*buf)->len && (max_len ? ((*buf)->len < max_len) : 1)) {
955 /* Set the new size of the string buffer to be the size needed
956 * to hold the resulting string (res) plus one byte for the
957 * terminating '\0'. If this size is greater than the max, set
958 * the new length to be the maximum allowed. */
959 if (max_len)
960 (*buf)->len = ((res + offset + 1) < max_len) ? (res + offset + 1) : max_len;
961 else
962 (*buf)->len = res + offset + 1;
964 if (!(*buf = ast_realloc(*buf, (*buf)->len + sizeof(*(*buf)))))
965 return AST_DYNSTR_BUILD_FAILED;
967 if (append)
968 (*buf)->str[offset] = '\0';
970 if (ts)
971 pthread_setspecific(ts->key, *buf);
973 /* va_end() and va_start() must be done before calling
974 * vsnprintf() again. */
975 return AST_DYNSTR_BUILD_RETRY;
978 return res;