strfuncs.c revision 86441ffc028f11857152c15fe7b0d24ff0874504
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2002-2012 Dovecot authors, see the included COPYING file */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen/* @UNSAFE: whole file */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "lib.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "printf-format-fix.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "strfuncs.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include <stdio.h>
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include <limits.h>
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include <ctype.h>
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#define STRCONCAT_BUFSIZE 512
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenint i_snprintf(char *dest, size_t max_chars, const char *format, ...)
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen{
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen va_list args;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen int ret;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_assert(max_chars < INT_MAX);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen va_start(args, format);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ret = vsnprintf(dest, max_chars, printf_format_fix_unsafe(format),
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen args);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen va_end(args);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_assert(ret >= 0);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return (unsigned int)ret < max_chars ? 0 : -1;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenchar *p_strdup(pool_t pool, const char *str)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen void *mem;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen size_t len;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (str == NULL)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return NULL;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen len = strlen(str) + 1;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen mem = p_malloc(pool, len);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen memcpy(mem, str, len);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return mem;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenchar *p_strdup_empty(pool_t pool, const char *str)
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen{
f24edebe360d3effe584a884aa7d119daf3fd371Aki Tuomi if (str == NULL || *str == '\0')
f24edebe360d3effe584a884aa7d119daf3fd371Aki Tuomi return NULL;
f24edebe360d3effe584a884aa7d119daf3fd371Aki Tuomi
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return p_strdup(pool, str);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenchar *p_strdup_until(pool_t pool, const void *start, const void *end)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen size_t size;
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen char *mem;
a326f9da3c18a4ccfb28e72f87161eaf3624eaf2Timo Sirainen
a326f9da3c18a4ccfb28e72f87161eaf3624eaf2Timo Sirainen i_assert((const char *) start <= (const char *) end);
a326f9da3c18a4ccfb28e72f87161eaf3624eaf2Timo Sirainen
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen size = (size_t) ((const char *) end - (const char *) start);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen mem = p_malloc(pool, size + 1);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen memcpy(mem, start, size);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return mem;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenchar *p_strndup(pool_t pool, const void *str, size_t max_chars)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen char *mem;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen size_t len;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_assert(max_chars != (size_t)-1);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (str == NULL)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return NULL;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen len = 0;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen while (len < max_chars && ((const char *) str)[len] != '\0')
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen len++;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen mem = p_malloc(pool, len+1);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen memcpy(mem, str, len);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen mem[len] = '\0';
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return mem;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
f24edebe360d3effe584a884aa7d119daf3fd371Aki Tuomichar *p_strdup_printf(pool_t pool, const char *format, ...)
f24edebe360d3effe584a884aa7d119daf3fd371Aki Tuomi{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen va_list args;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen char *ret;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen va_start(args, format);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ret = p_strdup_vprintf(pool, format, args);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen va_end(args);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return ret;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenchar *t_noalloc_strdup_vprintf(const char *format, va_list args,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen unsigned int *size_r)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#define SNPRINTF_INITIAL_EXTRA_SIZE 256
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen va_list args2;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen char *tmp;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen unsigned int init_size;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen int ret;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen VA_COPY(args2, args);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* the format string is modified only if %m exists in it. it happens
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen only in error conditions, so don't try to t_push() here since it'll
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen just slow down the normal code path. */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen format = printf_format_fix_get_len(format, &init_size);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen init_size += SNPRINTF_INITIAL_EXTRA_SIZE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen tmp = t_buffer_get(init_size);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ret = vsnprintf(tmp, init_size, format, args);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_assert(ret >= 0);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen *size_r = ret + 1;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if ((unsigned int)ret >= init_size) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* didn't fit with the first guess. now we know the size,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen so try again. */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen tmp = t_buffer_get(*size_r);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ret = vsnprintf(tmp, *size_r, format, args2);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_assert((unsigned int)ret == *size_r-1);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return tmp;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenchar *p_strdup_vprintf(pool_t pool, const char *format, va_list args)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen char *tmp, *buf;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen unsigned int size;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen tmp = t_noalloc_strdup_vprintf(format, args, &size);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (pool->datastack_pool) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen t_buffer_alloc(size);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return tmp;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen } else {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen buf = p_malloc(pool, size);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen memcpy(buf, tmp, size - 1);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return buf;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenchar *vstrconcat(const char *str1, va_list args, size_t *ret_len)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const char *str;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen char *temp;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen size_t bufsize, i, len;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (str1 == NULL)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return NULL;
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen str = str1;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen bufsize = STRCONCAT_BUFSIZE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen temp = t_buffer_get(bufsize);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i = 0;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen do {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen len = strlen(str);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (i + len >= bufsize) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* need more memory */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen bufsize = nearest_power(i + len + 1);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen temp = t_buffer_reget(temp, bufsize);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen memcpy(temp + i, str, len); i += len;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* next string */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str = va_arg(args, const char *);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen } while (str != NULL);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_assert(i < bufsize);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen temp[i++] = '\0';
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen *ret_len = i;
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen return temp;
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen}
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainenchar *p_strconcat(pool_t pool, const char *str1, ...)
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen va_list args;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen char *temp, *ret;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen size_t len;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen va_start(args, str1);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (pool->datastack_pool) {
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen ret = vstrconcat(str1, args, &len);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (ret != NULL)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen t_buffer_alloc(len);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen } else {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen T_BEGIN {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen temp = vstrconcat(str1, args, &len);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (temp == NULL)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ret = NULL;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen else {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen t_buffer_alloc(len);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ret = p_malloc(pool, len);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen memcpy(ret, temp, len);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen } T_END;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
83228b3f9f6ee8c62a61902e0203af9760f7b9b7Timo Sirainen
83228b3f9f6ee8c62a61902e0203af9760f7b9b7Timo Sirainen va_end(args);
83228b3f9f6ee8c62a61902e0203af9760f7b9b7Timo Sirainen return ret;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
83228b3f9f6ee8c62a61902e0203af9760f7b9b7Timo Sirainenconst char *t_strdup(const char *str)
83228b3f9f6ee8c62a61902e0203af9760f7b9b7Timo Sirainen{
83228b3f9f6ee8c62a61902e0203af9760f7b9b7Timo Sirainen return p_strdup(unsafe_data_stack_pool, str);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenchar *t_strdup_noconst(const char *str)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return p_strdup(unsafe_data_stack_pool, str);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenconst char *t_strdup_empty(const char *str)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return p_strdup_empty(unsafe_data_stack_pool, str);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenconst char *t_strdup_until(const void *start, const void *end)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen return p_strdup_until(unsafe_data_stack_pool, start, end);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenconst char *t_strndup(const void *str, size_t max_chars)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return p_strndup(unsafe_data_stack_pool, str, max_chars);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenconst char *t_strdup_printf(const char *format, ...)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen va_list args;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const char *ret;
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen va_start(args, format);
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen ret = p_strdup_vprintf(unsafe_data_stack_pool, format, args);
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen va_end(args);
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen return ret;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenconst char *t_strdup_vprintf(const char *format, va_list args)
{
return p_strdup_vprintf(unsafe_data_stack_pool, format, args);
}
const char *t_strconcat(const char *str1, ...)
{
va_list args;
const char *ret;
size_t len;
va_start(args, str1);
ret = vstrconcat(str1, args, &len);
if (ret != NULL)
t_buffer_alloc(len);
va_end(args);
return ret;
}
const char *t_strcut(const char *str, char cutchar)
{
const char *p;
for (p = str; *p != '\0'; p++) {
if (*p == cutchar)
return t_strdup_until(str, p);
}
return str;
}
int i_strocpy(char *dest, const char *src, size_t dstsize)
{
if (dstsize == 0)
return -1;
while (*src != '\0' && dstsize > 1) {
*dest++ = *src++;
dstsize--;
}
*dest = '\0';
return *src == '\0' ? 0 : -1;
}
char *str_ucase(char *str)
{
char *p;
for (p = str; *p != '\0'; p++)
*p = i_toupper(*p);
return str;
}
char *str_lcase(char *str)
{
char *p;
for (p = str; *p != '\0'; p++)
*p = i_tolower(*p);
return str;
}
const char *t_str_lcase(const char *str)
{
i_assert(str != NULL);
return str_lcase(t_strdup_noconst(str));
}
const char *t_str_ucase(const char *str)
{
i_assert(str != NULL);
return str_ucase(t_strdup_noconst(str));
}
int null_strcmp(const char *s1, const char *s2)
{
if (s1 == NULL)
return s2 == NULL ? 0 : -1;
if (s2 == NULL)
return 1;
return strcmp(s1, s2);
}
int i_memcasecmp(const void *p1, const void *p2, size_t size)
{
const unsigned char *s1 = p1;
const unsigned char *s2 = p2;
int ret;
while (size > 0) {
ret = i_toupper(*s1) - i_toupper(*s2);
if (ret != 0)
return ret;
s1++; s2++; size--;
}
return 0;
}
int bsearch_strcmp(const void *p1, const void *p2)
{
const char *key = p1;
const char *const *member = p2;
return strcmp(key, *member);
}
int i_strcmp_p(const void *p1, const void *p2)
{
const char *const *s1 = p1, *const *s2 = p2;
return strcmp(*s1, *s2);
}
int bsearch_strcasecmp(const void *p1, const void *p2)
{
const char *key = p1;
const char *const *member = p2;
return strcasecmp(key, *member);
}
int i_strcasecmp_p(const void *p1, const void *p2)
{
const char *const *s1 = p1, *const *s2 = p2;
return strcasecmp(*s1, *s2);
}
static char **
split_str(pool_t pool, const char *data, const char *separators, int spaces)
{
char **array;
char *str;
unsigned int count, alloc_count, new_alloc_count;
i_assert(*separators != '\0');
if (spaces) {
/* skip leading separators */
while (*data != '\0' && strchr(separators, *data) != NULL)
data++;
}
if (*data == '\0')
return p_new(pool, char *, 1);
str = p_strdup(pool, data);
alloc_count = 32;
array = p_new(pool, char *, alloc_count);
array[0] = str; count = 1;
while (*str != '\0') {
if (strchr(separators, *str) != NULL) {
/* separator found */
if (count+1 >= alloc_count) {
new_alloc_count = nearest_power(alloc_count+1);
array = p_realloc(pool, array,
sizeof(char *) * alloc_count,
sizeof(char *) *
new_alloc_count);
alloc_count = new_alloc_count;
}
*str = '\0';
if (spaces) {
while (str[1] != '\0' &&
strchr(separators, str[1]) != NULL)
str++;
/* ignore trailing separators */
if (str[1] == '\0')
break;
}
array[count++] = str+1;
}
str++;
}
i_assert(count < alloc_count);
array[count] = NULL;
return array;
}
const char **t_strsplit(const char *data, const char *separators)
{
return (const char **)split_str(unsafe_data_stack_pool, data,
separators, FALSE);
}
const char **t_strsplit_spaces(const char *data, const char *separators)
{
return (const char **)split_str(unsafe_data_stack_pool, data,
separators, TRUE);
}
char **p_strsplit(pool_t pool, const char *data, const char *separators)
{
return split_str(pool, data, separators, FALSE);
}
char **p_strsplit_spaces(pool_t pool, const char *data,
const char *separators)
{
return split_str(pool, data, separators, TRUE);
}
const char **t_strsplit_tab(const char *data)
{
const char **array;
char *dest;
unsigned int i, array_idx, array_size, dest_size;
if (*data == '\0')
return t_new(const char *, 1);
array_size = 1;
dest_size = 128;
dest = t_buffer_get(dest_size+1);
for (i = 0; data[i] != '\0'; i++) {
if (i >= dest_size) {
dest_size = nearest_power(dest_size+1);
dest = t_buffer_reget(dest, dest_size+1);
}
if (data[i] != '\t')
dest[i] = data[i];
else {
dest[i] = '\0';
array_size++;
}
}
i_assert(i <= dest_size);
dest[i] = '\0';
t_buffer_alloc(i+1);
dest_size = i;
array = t_new(const char *, array_size + 1);
array[0] = dest; array_idx = 1;
for (i = 0; i < dest_size; i++) {
if (dest[i] == '\0')
array[array_idx++] = dest+i+1;
}
i_assert(array_idx == array_size);
array[array_idx] = NULL;
return array;
}
void p_strsplit_free(pool_t pool, char **arr)
{
p_free(pool, arr[0]);
p_free(pool, arr);
}
unsigned int str_array_length(const char *const *arr)
{
unsigned int count;
if (arr == NULL)
return 0;
for (count = 0; *arr != NULL; arr++)
count++;
return count;
}
const char *t_strarray_join(const char *const *arr, const char *separator)
{
size_t alloc_len, sep_len, len, pos, needed_space;
char *str;
sep_len = strlen(separator);
alloc_len = 64;
str = t_buffer_get(alloc_len);
for (pos = 0; *arr != NULL; arr++) {
len = strlen(*arr);
needed_space = pos + len + sep_len + 1;
if (needed_space > alloc_len) {
alloc_len = nearest_power(needed_space);
str = t_buffer_reget(str, alloc_len);
}
if (pos != 0) {
memcpy(str + pos, separator, sep_len);
pos += sep_len;
}
memcpy(str + pos, *arr, len);
pos += len;
}
str[pos] = '\0';
t_buffer_alloc(pos + 1);
return str;
}
bool str_array_remove(const char **arr, const char *value)
{
const char **dest;
for (; *arr != NULL; arr++) {
if (strcmp(*arr, value) == 0) {
/* found it. now move the rest. */
for (dest = arr, arr++; *arr != NULL; arr++, dest++)
*dest = *arr;
*dest = NULL;
return TRUE;
}
}
return FALSE;
}
bool str_array_find(const char *const *arr, const char *value)
{
for (; *arr != NULL; arr++) {
if (strcmp(*arr, value) == 0)
return TRUE;
}
return FALSE;
}
bool str_array_icase_find(const char *const *arr, const char *value)
{
for (; *arr != NULL; arr++) {
if (strcasecmp(*arr, value) == 0)
return TRUE;
}
return FALSE;
}
const char **p_strarray_dup(pool_t pool, const char *const *arr)
{
unsigned int i;
const char **ret;
char *p;
size_t len, size = sizeof(const char *);
for (i = 0; arr[i] != NULL; i++)
size += sizeof(const char *) + strlen(arr[i]) + 1;
ret = p_malloc(pool, size);
p = PTR_OFFSET(ret, sizeof(const char *) * (i + 1));
for (i = 0; arr[i] != NULL; i++) {
len = strlen(arr[i]) + 1;
memcpy(p, arr[i], len);
ret[i] = p;
p += len;
}
i_assert(PTR_OFFSET(ret, size) == (void *)p);
return ret;
}
const char *dec2str(uintmax_t number)
{
char *buffer;
int pos;
pos = MAX_INT_STRLEN;
buffer = t_malloc(pos);
buffer[--pos] = '\0';
do {
buffer[--pos] = (number % 10) + '0';
number /= 10;
} while (number != 0 && pos >= 0);
i_assert(pos >= 0);
return buffer + pos;
}