00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifndef _ASTERISK_STRINGS_H
00024 #define _ASTERISK_STRINGS_H
00025
00026
00027
00028 #include <ctype.h>
00029
00030 #include "asterisk/utils.h"
00031 #include "asterisk/threadstorage.h"
00032
00033 #if defined(DEBUG_OPAQUE)
00034 #define __AST_STR_USED used2
00035 #define __AST_STR_LEN len2
00036 #define __AST_STR_STR str2
00037 #define __AST_STR_TS ts2
00038 #else
00039 #define __AST_STR_USED used
00040 #define __AST_STR_LEN len
00041 #define __AST_STR_STR str
00042 #define __AST_STR_TS ts
00043 #endif
00044
00045
00046
00047 #define AS_OR(a,b) (a && ast_str_strlen(a)) ? ast_str_buffer(a) : (b)
00048
00049 #ifdef AST_DEVMODE
00050 #define ast_strlen_zero(foo) _ast_strlen_zero(foo, __FILE__, __PRETTY_FUNCTION__, __LINE__)
00051 static force_inline int _ast_strlen_zero(const char *s, const char *file, const char *function, int line)
00052 {
00053 if (!s || (*s == '\0')) {
00054 return 1;
00055 }
00056 if (!strcmp(s, "(null)")) {
00057 ast_log(__LOG_WARNING, file, line, function, "Possible programming error: \"(null)\" is not NULL!\n");
00058 }
00059 return 0;
00060 }
00061
00062 #else
00063 static force_inline int attribute_pure ast_strlen_zero(const char *s)
00064 {
00065 return (!s || (*s == '\0'));
00066 }
00067 #endif
00068
00069
00070
00071
00072 #define S_OR(a, b) ({typeof(&((a)[0])) __x = (a); ast_strlen_zero(__x) ? (b) : __x;})
00073
00074
00075
00076
00077
00078 #define S_COR(a, b, c) ({typeof(&((b)[0])) __x = (b); (a) && !ast_strlen_zero(__x) ? (__x) : (c);})
00079
00080
00081
00082
00083
00084
00085 AST_INLINE_API(
00086 char * attribute_pure ast_skip_blanks(const char *str),
00087 {
00088 while (*str && ((unsigned char) *str) < 33)
00089 str++;
00090 return (char *) str;
00091 }
00092 )
00093
00094
00095
00096
00097
00098
00099 AST_INLINE_API(
00100 char *ast_trim_blanks(char *str),
00101 {
00102 char *work = str;
00103
00104 if (work) {
00105 work += strlen(work) - 1;
00106
00107
00108
00109
00110
00111
00112 while ((work >= str) && ((unsigned char) *work) < 33)
00113 *(work--) = '\0';
00114 }
00115 return str;
00116 }
00117 )
00118
00119
00120
00121
00122
00123
00124 AST_INLINE_API(
00125 char * attribute_pure ast_skip_nonblanks(const char *str),
00126 {
00127 while (*str && ((unsigned char) *str) > 32)
00128 str++;
00129 return (char *) str;
00130 }
00131 )
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 AST_INLINE_API(
00143 char *ast_strip(char *s),
00144 {
00145 if ((s = ast_skip_blanks(s))) {
00146 ast_trim_blanks(s);
00147 }
00148 return s;
00149 }
00150 )
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176 char *ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes);
00177
00178
00179
00180
00181
00182
00183 char *ast_unescape_semicolon(char *s);
00184
00185
00186
00187
00188
00189
00190 char *ast_unescape_c(char *s);
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207 AST_INLINE_API(
00208 void ast_copy_string(char *dst, const char *src, size_t size),
00209 {
00210 while (*src && size) {
00211 *dst++ = *src++;
00212 size--;
00213 }
00214 if (__builtin_expect(!size, 0))
00215 dst--;
00216 *dst = '\0';
00217 }
00218 )
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234 int ast_build_string(char **buffer, size_t *space, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248 int ast_build_string_va(char **buffer, size_t *space, const char *fmt, va_list ap) __attribute__((format(printf, 3, 0)));
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260 int attribute_pure ast_true(const char *val);
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272 int attribute_pure ast_false(const char *val);
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284 void ast_join(char *s, size_t len, char * const w[]);
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295 int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed);
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305 int ast_get_timeval(const char *src, struct timeval *tv, struct timeval _default, int *consumed);
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359 struct ast_str {
00360 size_t __AST_STR_LEN;
00361 size_t __AST_STR_USED;
00362 struct ast_threadstorage *__AST_STR_TS;
00363 #define DS_MALLOC ((struct ast_threadstorage *)1)
00364 #define DS_ALLOCA ((struct ast_threadstorage *)2)
00365 #define DS_STATIC ((struct ast_threadstorage *)3)
00366 char __AST_STR_STR[0];
00367 };
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380 #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
00381 #define ast_str_create(a) _ast_str_create(a,__FILE__,__LINE__,__PRETTY_FUNCTION__)
00382 AST_INLINE_API(
00383 struct ast_str * attribute_malloc _ast_str_create(size_t init_len,
00384 const char *file, int lineno, const char *func),
00385 {
00386 struct ast_str *buf;
00387
00388 buf = (struct ast_str *)__ast_calloc(1, sizeof(*buf) + init_len, file, lineno, func);
00389 if (buf == NULL)
00390 return NULL;
00391
00392 buf->__AST_STR_LEN = init_len;
00393 buf->__AST_STR_USED = 0;
00394 buf->__AST_STR_TS = DS_MALLOC;
00395
00396 return buf;
00397 }
00398 )
00399 #else
00400 AST_INLINE_API(
00401 struct ast_str * attribute_malloc ast_str_create(size_t init_len),
00402 {
00403 struct ast_str *buf;
00404
00405 buf = (struct ast_str *)ast_calloc(1, sizeof(*buf) + init_len);
00406 if (buf == NULL)
00407 return NULL;
00408
00409 buf->__AST_STR_LEN = init_len;
00410 buf->__AST_STR_USED = 0;
00411 buf->__AST_STR_TS = DS_MALLOC;
00412
00413 return buf;
00414 }
00415 )
00416 #endif
00417
00418
00419
00420
00421 AST_INLINE_API(
00422 void ast_str_reset(struct ast_str *buf),
00423 {
00424 if (buf) {
00425 buf->__AST_STR_USED = 0;
00426 if (buf->__AST_STR_LEN) {
00427 buf->__AST_STR_STR[0] = '\0';
00428 }
00429 }
00430 }
00431 )
00432
00433
00434
00435
00436 AST_INLINE_API(
00437 void ast_str_update(struct ast_str *buf),
00438 {
00439 buf->__AST_STR_USED = strlen(buf->__AST_STR_STR);
00440 }
00441 )
00442
00443
00444
00445
00446 AST_INLINE_API(
00447 void ast_str_trim_blanks(struct ast_str *buf),
00448 {
00449 if (!buf) {
00450 return;
00451 }
00452 while (buf->__AST_STR_USED && buf->__AST_STR_STR[buf->__AST_STR_USED - 1] < 33) {
00453 buf->__AST_STR_STR[--(buf->__AST_STR_USED)] = '\0';
00454 }
00455 }
00456 )
00457
00458
00459
00460
00461 AST_INLINE_API(
00462 size_t attribute_pure ast_str_strlen(struct ast_str *buf),
00463 {
00464 return buf->__AST_STR_USED;
00465 }
00466 )
00467
00468
00469
00470
00471
00472 AST_INLINE_API(
00473 size_t attribute_pure ast_str_size(struct ast_str *buf),
00474 {
00475 return buf->__AST_STR_LEN;
00476 }
00477 )
00478
00479
00480
00481
00482
00483 AST_INLINE_API(
00484 char * attribute_pure ast_str_buffer(struct ast_str *buf),
00485 {
00486 return buf->__AST_STR_STR;
00487 }
00488 )
00489
00490
00491
00492
00493
00494
00495 AST_INLINE_API(
00496 char *ast_str_truncate(struct ast_str *buf, ssize_t len),
00497 {
00498 if (len < 0) {
00499 buf->__AST_STR_USED += ((ssize_t) abs(len)) > (ssize_t) buf->__AST_STR_USED ? -buf->__AST_STR_USED : len;
00500 } else {
00501 buf->__AST_STR_USED = len;
00502 }
00503 buf->__AST_STR_STR[buf->__AST_STR_USED] = '\0';
00504 return buf->__AST_STR_STR;
00505 }
00506 )
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516 #if defined(DEBUG_THREADLOCALS)
00517 #define _DB1(x) x
00518 #else
00519 #define _DB1(x)
00520 #endif
00521
00522
00523
00524
00525 #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
00526 AST_INLINE_API(
00527 int _ast_str_make_space(struct ast_str **buf, size_t new_len, const char *file, int lineno, const char *function),
00528 {
00529 struct ast_str *old_buf = *buf;
00530
00531 if (new_len <= (*buf)->__AST_STR_LEN)
00532 return 0;
00533 if ((*buf)->__AST_STR_TS == DS_ALLOCA || (*buf)->__AST_STR_TS == DS_STATIC)
00534 return -1;
00535 *buf = (struct ast_str *)__ast_realloc(*buf, new_len + sizeof(struct ast_str), file, lineno, function);
00536 if (*buf == NULL) {
00537 *buf = old_buf;
00538 return -1;
00539 }
00540 if ((*buf)->__AST_STR_TS != DS_MALLOC) {
00541 pthread_setspecific((*buf)->__AST_STR_TS->key, *buf);
00542 _DB1(__ast_threadstorage_object_replace(old_buf, *buf, new_len + sizeof(struct ast_str));)
00543 }
00544
00545 (*buf)->__AST_STR_LEN = new_len;
00546 return 0;
00547 }
00548 )
00549 #define ast_str_make_space(a,b) _ast_str_make_space(a,b,__FILE__,__LINE__,__PRETTY_FUNCTION__)
00550 #else
00551 AST_INLINE_API(
00552 int ast_str_make_space(struct ast_str **buf, size_t new_len),
00553 {
00554 struct ast_str *old_buf = *buf;
00555
00556 if (new_len <= (*buf)->__AST_STR_LEN)
00557 return 0;
00558 if ((*buf)->__AST_STR_TS == DS_ALLOCA || (*buf)->__AST_STR_TS == DS_STATIC)
00559 return -1;
00560 *buf = (struct ast_str *)ast_realloc(*buf, new_len + sizeof(struct ast_str));
00561 if (*buf == NULL) {
00562 *buf = old_buf;
00563 return -1;
00564 }
00565 if ((*buf)->__AST_STR_TS != DS_MALLOC) {
00566 pthread_setspecific((*buf)->__AST_STR_TS->key, *buf);
00567 _DB1(__ast_threadstorage_object_replace(old_buf, *buf, new_len + sizeof(struct ast_str));)
00568 }
00569
00570 (*buf)->__AST_STR_LEN = new_len;
00571 return 0;
00572 }
00573 )
00574 #endif
00575
00576 AST_INLINE_API(
00577 int ast_str_copy_string(struct ast_str **dst, struct ast_str *src),
00578 {
00579
00580
00581 if (src->__AST_STR_USED + 1 > (*dst)->__AST_STR_LEN) {
00582 if (ast_str_make_space(dst, src->__AST_STR_USED + 1)) {
00583 return -1;
00584 }
00585 }
00586
00587 memcpy((*dst)->__AST_STR_STR, src->__AST_STR_STR, src->__AST_STR_USED + 1);
00588 (*dst)->__AST_STR_USED = src->__AST_STR_USED;
00589 return 0;
00590 }
00591 )
00592
00593 #define ast_str_alloca(init_len) \
00594 ({ \
00595 struct ast_str *__ast_str_buf; \
00596 __ast_str_buf = alloca(sizeof(*__ast_str_buf) + init_len); \
00597 __ast_str_buf->__AST_STR_LEN = init_len; \
00598 __ast_str_buf->__AST_STR_USED = 0; \
00599 __ast_str_buf->__AST_STR_TS = DS_ALLOCA; \
00600 __ast_str_buf->__AST_STR_STR[0] = '\0'; \
00601 (__ast_str_buf); \
00602 })
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635 #if !defined(DEBUG_THREADLOCALS)
00636 AST_INLINE_API(
00637 struct ast_str *ast_str_thread_get(struct ast_threadstorage *ts,
00638 size_t init_len),
00639 {
00640 struct ast_str *buf;
00641
00642 buf = (struct ast_str *)ast_threadstorage_get(ts, sizeof(*buf) + init_len);
00643 if (buf == NULL)
00644 return NULL;
00645
00646 if (!buf->__AST_STR_LEN) {
00647 buf->__AST_STR_LEN = init_len;
00648 buf->__AST_STR_USED = 0;
00649 buf->__AST_STR_TS = ts;
00650 }
00651
00652 return buf;
00653 }
00654 )
00655 #else
00656 AST_INLINE_API(
00657 struct ast_str *__ast_str_thread_get(struct ast_threadstorage *ts,
00658 size_t init_len, const char *file, const char *function, unsigned int line),
00659 {
00660 struct ast_str *buf;
00661
00662 buf = (struct ast_str *)__ast_threadstorage_get(ts, sizeof(*buf) + init_len, file, function, line);
00663 if (buf == NULL)
00664 return NULL;
00665
00666 if (!buf->__AST_STR_LEN) {
00667 buf->__AST_STR_LEN = init_len;
00668 buf->__AST_STR_USED = 0;
00669 buf->__AST_STR_TS = ts;
00670 }
00671
00672 return buf;
00673 }
00674 )
00675
00676 #define ast_str_thread_get(ts, init_len) __ast_str_thread_get(ts, init_len, __FILE__, __PRETTY_FUNCTION__, __LINE__)
00677 #endif
00678
00679
00680
00681
00682
00683
00684
00685 enum {
00686
00687
00688 AST_DYNSTR_BUILD_FAILED = -1,
00689
00690
00691
00692
00693
00694 AST_DYNSTR_BUILD_RETRY = -2
00695 };
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718 #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
00719 int __attribute__((format(printf, 4, 0))) __ast_debug_str_helper(struct ast_str **buf, ssize_t max_len,
00720 int append, const char *fmt, va_list ap, const char *file, int lineno, const char *func);
00721 #define __ast_str_helper(a,b,c,d,e) __ast_debug_str_helper(a,b,c,d,e,__FILE__,__LINE__,__PRETTY_FUNCTION__)
00722 #else
00723 int __attribute__((format(printf, 4, 0))) __ast_str_helper(struct ast_str **buf, ssize_t max_len,
00724 int append, const char *fmt, va_list ap);
00725 #endif
00726 char *__ast_str_helper2(struct ast_str **buf, ssize_t max_len,
00727 const char *src, size_t maxsrc, int append, int escapecommas);
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767 AST_INLINE_API(int __attribute__((format(printf, 3, 0))) ast_str_set_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap),
00768 {
00769 return __ast_str_helper(buf, max_len, 0, fmt, ap);
00770 }
00771 )
00772
00773
00774
00775
00776
00777
00778 AST_INLINE_API(int __attribute__((format(printf, 3, 0))) ast_str_append_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap),
00779 {
00780 return __ast_str_helper(buf, max_len, 1, fmt, ap);
00781 }
00782 )
00783
00784
00785 AST_INLINE_API(char *ast_str_set_substr(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc),
00786 {
00787 return __ast_str_helper2(buf, maxlen, src, maxsrc, 0, 0);
00788 }
00789 )
00790
00791
00792 AST_INLINE_API(char *ast_str_append_substr(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc),
00793 {
00794 return __ast_str_helper2(buf, maxlen, src, maxsrc, 1, 0);
00795 }
00796 )
00797
00798
00799 AST_INLINE_API(char *ast_str_set_escapecommas(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc),
00800 {
00801 return __ast_str_helper2(buf, maxlen, src, maxsrc, 0, 1);
00802 }
00803 )
00804
00805
00806 AST_INLINE_API(char *ast_str_append_escapecommas(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc),
00807 {
00808 return __ast_str_helper2(buf, maxlen, src, maxsrc, 1, 1);
00809 }
00810 )
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829 AST_INLINE_API(
00830 int __attribute__((format(printf, 3, 4))) ast_str_set(
00831 struct ast_str **buf, ssize_t max_len, const char *fmt, ...),
00832 {
00833 int res;
00834 va_list ap;
00835
00836 va_start(ap, fmt);
00837 res = ast_str_set_va(buf, max_len, fmt, ap);
00838 va_end(ap);
00839
00840 return res;
00841 }
00842 )
00843
00844
00845
00846
00847
00848
00849
00850 AST_INLINE_API(
00851 int __attribute__((format(printf, 3, 4))) ast_str_append(
00852 struct ast_str **buf, ssize_t max_len, const char *fmt, ...),
00853 {
00854 int res;
00855 va_list ap;
00856
00857 va_start(ap, fmt);
00858 res = ast_str_append_va(buf, max_len, fmt, ap);
00859 va_end(ap);
00860
00861 return res;
00862 }
00863 )
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873 static force_inline int attribute_pure ast_str_hash(const char *str)
00874 {
00875 int hash = 5381;
00876
00877 while (*str)
00878 hash = hash * 33 ^ *str++;
00879
00880 return abs(hash);
00881 }
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898 static force_inline int ast_str_hash_add(const char *str, int hash)
00899 {
00900 while (*str)
00901 hash = hash * 33 ^ *str++;
00902
00903 return abs(hash);
00904 }
00905
00906
00907
00908
00909
00910
00911
00912
00913 static force_inline int attribute_pure ast_str_case_hash(const char *str)
00914 {
00915 int hash = 5381;
00916
00917 while (*str) {
00918 hash = hash * 33 ^ tolower(*str++);
00919 }
00920
00921 return abs(hash);
00922 }
00923
00924 #endif