diff options
Diffstat (limited to 'include/asterisk/strings.h')
-rw-r--r-- | include/asterisk/strings.h | 244 |
1 files changed, 239 insertions, 5 deletions
diff --git a/include/asterisk/strings.h b/include/asterisk/strings.h index 43d5bfc41..84782a3ac 100644 --- a/include/asterisk/strings.h +++ b/include/asterisk/strings.h @@ -23,14 +23,17 @@ #ifndef _ASTERISK_STRINGS_H #define _ASTERISK_STRINGS_H +#define DEBUG_OPAQUE + #include <ctype.h> -#include "asterisk/inline_api.h" #include "asterisk/utils.h" #include "asterisk/threadstorage.h" /* You may see casts in this header that may seem useless but they ensure this file is C++ clean */ +#define AS_OR(a,b) ast_str_strlen(a) ? ast_str_buffer(a) : (b) + #ifdef AST_DEVMODE #define ast_strlen_zero(foo) _ast_strlen_zero(foo, __FILE__, __PRETTY_FUNCTION__, __LINE__) static force_inline int _ast_strlen_zero(const char *s, const char *file, const char *function, int line) @@ -202,7 +205,6 @@ void ast_copy_string(char *dst, const char *src, size_t size), } ) - /*! \brief Build a string in a buffer, designed to be called repeatedly @@ -338,13 +340,23 @@ int ast_get_timeval(const char *src, struct timeval *tv, struct timeval _default * struct ast_threadstorage pointer. */ struct ast_str { +#ifdef DEBUG_OPAQUE + size_t len2; + size_t used2; + struct ast_threadstorage *ts2; +#else size_t len; /*!< The current maximum length of the string */ size_t used; /*!< Amount of space used */ struct ast_threadstorage *ts; /*!< What kind of storage is this ? */ +#endif #define DS_MALLOC ((struct ast_threadstorage *)1) #define DS_ALLOCA ((struct ast_threadstorage *)2) #define DS_STATIC ((struct ast_threadstorage *)3) /* not supported yet */ +#ifdef DEBUG_OPAQUE + char str2[0]; +#else char str[0]; /*!< The string buffer */ +#endif }; /*! @@ -366,10 +378,16 @@ struct ast_str * attribute_malloc ast_str_create(size_t init_len), buf = (struct ast_str *)ast_calloc(1, sizeof(*buf) + init_len); if (buf == NULL) return NULL; - + +#ifdef DEBUG_OPAQUE + buf->len2 = init_len; + buf->used2 = 0; + buf->ts2 = DS_MALLOC; +#else buf->len = init_len; buf->used = 0; buf->ts = DS_MALLOC; +#endif return buf; } @@ -382,9 +400,15 @@ AST_INLINE_API( void ast_str_reset(struct ast_str *buf), { if (buf) { +#ifdef DEBUG_OPAQUE + buf->used2 = 0; + if (buf->len2) + buf->str2[0] = '\0'; +#else buf->used = 0; if (buf->len) buf->str[0] = '\0'; +#endif } } ) @@ -398,12 +422,83 @@ void ast_str_trim_blanks(struct ast_str *buf), if (!buf) { return; } +#ifdef DEBUG_OPAQUE + while (buf->used2 && buf->str2[buf->used2 - 1] < 33) { + buf->str2[--(buf->used2)] = '\0'; + } +#else while (buf->used && buf->str[buf->used - 1] < 33) { buf->str[--(buf->used)] = '\0'; } +#endif +} +) + +/*!\brief Returns the current length of the string stored within buf. + * \param A pointer to the ast_str string. + */ +AST_INLINE_API( +size_t ast_str_strlen(struct ast_str *buf), +{ +#ifdef DEBUG_OPAQUE + return buf->used2; +#else + return buf->used; +#endif +} +) + +/*!\brief Returns the current maximum length (without reallocation) of the current buffer. + * \param A pointer to the ast_str string. + */ +AST_INLINE_API( +size_t ast_str_size(struct ast_str *buf), +{ +#ifdef DEBUG_OPAQUE + return buf->len2; +#else + return buf->len; +#endif } ) +/*!\brief Returns the string buffer within the ast_str buf. + * \param A pointer to the ast_str string. + */ +AST_INLINE_API( +attribute_pure char *ast_str_buffer(struct ast_str *buf), +{ +#ifdef DEBUG_OPAQUE + return buf->str2; +#else + return buf->str; +#endif +} +) + +AST_INLINE_API( +char *ast_str_truncate(struct ast_str *buf, size_t len), +{ +#ifdef DEBUG_OPAQUE + if (len < 0) { + buf->used2 += len; + } else { + buf->used2 = len; + } + buf->str2[buf->used2] = '\0'; + return buf->str2; +#else + if (len < 0) { + buf->used += len; + } else { + buf->used = len; + } + buf->str[buf->used] = '\0'; + return buf->str; +#endif +} +) + /* * AST_INLINE_API() is a macro that takes a block of code as an argument. * Using preprocessor #directives in the argument is not supported by all @@ -427,6 +522,23 @@ int _ast_str_make_space(struct ast_str **buf, size_t new_len, const char *file, { struct ast_str *old_buf = *buf; +#ifdef DEBUG_OPAQUE + if (new_len <= (*buf)->len2) + return 0; /* success */ + if ((*buf)->ts2 == DS_ALLOCA || (*buf)->ts2 == DS_STATIC) + return -1; /* cannot extend */ + *buf = (struct ast_str *)__ast_realloc(*buf, new_len + sizeof(struct ast_str), file, lineno, function); + if (*buf == NULL) { + *buf = old_buf; + return -1; + } + if ((*buf)->ts2 != DS_MALLOC) { + pthread_setspecific((*buf)->ts2->key, *buf); + _DB1(__ast_threadstorage_object_replace(old_buf, *buf, new_len + sizeof(struct ast_str));) + } + + (*buf)->len2 = new_len; +#else if (new_len <= (*buf)->len) return 0; /* success */ if ((*buf)->ts == DS_ALLOCA || (*buf)->ts == DS_STATIC) @@ -442,6 +554,7 @@ int _ast_str_make_space(struct ast_str **buf, size_t new_len, const char *file, } (*buf)->len = new_len; +#endif return 0; } ) @@ -452,6 +565,23 @@ int ast_str_make_space(struct ast_str **buf, size_t new_len), { struct ast_str *old_buf = *buf; +#ifdef DEBUG_OPAQUE + if (new_len <= (*buf)->len2) + return 0; /* success */ + if ((*buf)->ts2 == DS_ALLOCA || (*buf)->ts2 == DS_STATIC) + return -1; /* cannot extend */ + *buf = (struct ast_str *)ast_realloc(*buf, new_len + sizeof(struct ast_str)); + if (*buf == NULL) { + *buf = old_buf; + return -1; + } + if ((*buf)->ts2 != DS_MALLOC) { + pthread_setspecific((*buf)->ts2->key, *buf); + _DB1(__ast_threadstorage_object_replace(old_buf, *buf, new_len + sizeof(struct ast_str));) + } + + (*buf)->len2 = new_len; +#else if (new_len <= (*buf)->len) return 0; /* success */ if ((*buf)->ts == DS_ALLOCA || (*buf)->ts == DS_STATIC) @@ -467,11 +597,24 @@ int ast_str_make_space(struct ast_str **buf, size_t new_len), } (*buf)->len = new_len; +#endif return 0; } ) #endif +#ifdef DEBUG_OPAQUE +#define ast_str_alloca(init_len) \ + ({ \ + struct ast_str *__ast_str_buf; \ + __ast_str_buf = alloca(sizeof(*__ast_str_buf) + init_len); \ + __ast_str_buf->len2 = init_len; \ + __ast_str_buf->used2 = 0; \ + __ast_str_buf->ts2 = DS_ALLOCA; \ + __ast_str_buf->str2[0] = '\0'; \ + (__ast_str_buf); \ + }) +#else #define ast_str_alloca(init_len) \ ({ \ struct ast_str *__ast_str_buf; \ @@ -482,6 +625,7 @@ int ast_str_make_space(struct ast_str **buf, size_t new_len), __ast_str_buf->str[0] = '\0'; \ (__ast_str_buf); \ }) +#endif /*! * \brief Retrieve a thread locally stored dynamic string @@ -524,12 +668,20 @@ struct ast_str *ast_str_thread_get(struct ast_threadstorage *ts, buf = (struct ast_str *)ast_threadstorage_get(ts, sizeof(*buf) + init_len); if (buf == NULL) return NULL; - + +#ifdef DEBUG_OPAQUE + if (!buf->len2) { + buf->len2 = init_len; + buf->used2 = 0; + buf->ts2 = ts; + } +#else if (!buf->len) { buf->len = init_len; buf->used = 0; buf->ts = ts; } +#endif return buf; } @@ -544,12 +696,20 @@ struct ast_str *__ast_str_thread_get(struct ast_threadstorage *ts, buf = (struct ast_str *)__ast_threadstorage_get(ts, sizeof(*buf) + init_len, file, function, line); if (buf == NULL) return NULL; - + +#ifdef DEBUG_OPAQUE + if (!buf->len2) { + buf->len2 = init_len; + buf->used2 = 0; + buf->ts2 = ts; + } +#else if (!buf->len) { buf->len = init_len; buf->used = 0; buf->ts = ts; } +#endif return buf; } @@ -599,6 +759,8 @@ enum { */ int __attribute__((format(printf, 4, 0))) __ast_str_helper(struct ast_str **buf, size_t max_len, int append, const char *fmt, va_list ap); +char *__ast_str_helper2(struct ast_str **buf, size_t max_len, + const char *src, size_t maxsrc, int append, int escapecommas); /*! * \brief Set a dynamic string from a va_list @@ -655,6 +817,78 @@ AST_INLINE_API(int __attribute__((format(printf, 3, 0))) ast_str_append_va(struc } ) +/*!\brief Set a dynamic string to a non-NULL terminated substring. */ +AST_INLINE_API(char *ast_str_set_substr(struct ast_str **buf, size_t maxlen, const char *src, size_t maxsrc), +{ + return __ast_str_helper2(buf, maxlen, src, maxsrc, 0, 0); +} +) + +/*!\brief Append a non-NULL terminated substring to the end of a dynamic string. */ +AST_INLINE_API(char *ast_str_append_substr(struct ast_str **buf, size_t maxlen, const char *src, size_t maxsrc), +{ + return __ast_str_helper2(buf, maxlen, src, maxsrc, 1, 0); +} +) + +/*!\brief Set a dynamic string to a non-NULL terminated substring, with escaping of commas. */ +AST_INLINE_API(char *ast_str_set_escapecommas(struct ast_str **buf, size_t maxlen, const char *src, size_t maxsrc), +{ + return __ast_str_helper2(buf, maxlen, src, maxsrc, 0, 1); +} +) + +/*!\brief Append a non-NULL terminated substring to the end of a dynamic string, with escaping of commas. */ +AST_INLINE_API(char *ast_str_append_escapecommas(struct ast_str **buf, size_t maxlen, const char *src, size_t maxsrc), +{ + return __ast_str_helper2(buf, maxlen, src, maxsrc, 1, 1); +} +) + +/*!\brief Wrapper for SQLGetData to use with dynamic strings + * \param buf Address of the pointer to the ast_str structure. + * \param maxlen The maximum size of the resulting string, or 0 for no limit. + * \param StatementHandle The statement handle from which to retrieve data. + * \param ColumnNumber Column number (1-based offset) for which to retrieve data. + * \param TargetType The SQL constant indicating what kind of data is to be retrieved (usually SQL_CHAR) + * \param StrLen_or_Ind A pointer to a length indicator, specifying the total length of data. + */ +#ifdef USE_ODBC +#include <sql.h> +#include <sqlext.h> +#include <sqltypes.h> + +AST_INLINE_API(SQLRETURN ast_str_SQLGetData(struct ast_str **buf, size_t maxlen, SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, SQLLEN *StrLen_or_Ind), +{ + SQLRETURN res; + if (maxlen == 0) { +#ifdef DEBUG_OPAQUE + if (SQLGetData(StatementHandle, ColumnNumber, TargetType, (*buf)->str2, 0, StrLen_or_Ind) == SQL_SUCCESS_WITH_INFO) { + ast_str_make_space(buf, *StrLen_or_Ind + 1); + } + maxlen = (*buf)->len2; + } else if (maxlen > 0) { + ast_str_make_space(buf, maxlen); + } + res = SQLGetData(StatementHandle, ColumnNumber, TargetType, (*buf)->str2, maxlen, StrLen_or_Ind); + (*buf)->used2 = *StrLen_or_Ind; +#else + if (SQLGetData(StatementHandle, ColumnNumber, TargetType, (*buf)->str, 0, StrLen_or_Ind) == SQL_SUCCESS_WITH_INFO) { + ast_str_make_space(buf, *StrLen_or_Ind + 1); + } + maxlen = (*buf)->len; + } else if (maxlen > 0) { + ast_str_make_space(buf, maxlen); + } + res = SQLGetData(StatementHandle, ColumnNumber, TargetType, (*buf)->str, maxlen, StrLen_or_Ind); + (*buf)->used = *StrLen_or_Ind; +#endif + return res; +} +) +#endif /* defined(USE_ODBC) */ + + /*! * \brief Set a dynamic string using variable arguments * |