strfuncs.c revision a8319b1f667a808f335447e9fa10ff66b99705c5
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2002-2015 Dovecot authors, see the included COPYING file */
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen/* @UNSAFE: whole file */
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "lib.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "printf-format-fix.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "strfuncs.h"
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include <stdio.h>
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include <limits.h>
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include <ctype.h>
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#define STRCONCAT_BUFSIZE 512
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenconst unsigned char uchar_nul = '\0';
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenint i_snprintf(char *dest, size_t max_chars, const char *format, ...)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen va_list args;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen int ret;
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen i_assert(max_chars < INT_MAX);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen va_start(args, format);
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen ret = vsnprintf(dest, max_chars, printf_format_fix_unsafe(format),
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen args);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen va_end(args);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen i_assert(ret >= 0);
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen return (unsigned int)ret < max_chars ? 0 : -1;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainenchar *p_strdup(pool_t pool, const char *str)
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen{
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen void *mem;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen size_t len;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (str == NULL)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return NULL;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen len = strlen(str) + 1;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen mem = p_malloc(pool, len);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen memcpy(mem, str, len);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return mem;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenvoid *p_memdup(pool_t pool, const void *data, size_t size)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen void *mem;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen mem = p_malloc(pool, size);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen memcpy(mem, data, size);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return mem;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenchar *p_strdup_empty(pool_t pool, const char *str)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (str == NULL || *str == '\0')
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return NULL;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return p_strdup(pool, str);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
46b823ac3bce2c0f9f0fc73911e48d3a77b04fbeTimo Sirainenchar *p_strdup_until(pool_t pool, const void *start, const void *end)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen size_t size;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen char *mem;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen i_assert((const char *) start <= (const char *) end);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen size = (size_t) ((const char *) end - (const char *) start);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
e245fb1302121d2bc2580f61e040c2c8a558ee9eTimo Sirainen mem = p_malloc(pool, size + 1);
e245fb1302121d2bc2580f61e040c2c8a558ee9eTimo Sirainen memcpy(mem, start, size);
e245fb1302121d2bc2580f61e040c2c8a558ee9eTimo Sirainen return mem;
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenchar *p_strndup(pool_t pool, const void *str, size_t max_chars)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen char *mem;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen size_t len;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen i_assert(max_chars != (size_t)-1);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (str == NULL)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return NULL;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen len = 0;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen while (len < max_chars && ((const char *) str)[len] != '\0')
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen len++;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen mem = p_malloc(pool, len+1);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen memcpy(mem, str, len);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen mem[len] = '\0';
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return mem;
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenchar *p_strdup_printf(pool_t pool, const char *format, ...)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen va_list args;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen char *ret;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen va_start(args, format);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen ret = p_strdup_vprintf(pool, format, args);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen va_end(args);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return ret;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen}
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainenchar *t_noalloc_strdup_vprintf(const char *format, va_list args,
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen unsigned int *size_r)
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen{
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen#define SNPRINTF_INITIAL_EXTRA_SIZE 256
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen va_list args2;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen char *tmp;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen unsigned int init_size;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen int ret;
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen#ifdef DEBUG
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen int old_errno = errno;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#endif
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen VA_COPY(args2, args);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen /* the format string is modified only if %m exists in it. it happens
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen only in error conditions, so don't try to t_push() here since it'll
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen just slow down the normal code path. */
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen format = printf_format_fix_get_len(format, &init_size);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen init_size += SNPRINTF_INITIAL_EXTRA_SIZE;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen tmp = t_buffer_get(init_size);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen ret = vsnprintf(tmp, init_size, format, args);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen i_assert(ret >= 0);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen *size_r = ret + 1;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen if ((unsigned int)ret >= init_size) {
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen /* didn't fit with the first guess. now we know the size,
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen so try again. */
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen tmp = t_buffer_get(*size_r);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen ret = vsnprintf(tmp, *size_r, format, args2);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen i_assert((unsigned int)ret == *size_r-1);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen }
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen#ifdef DEBUG
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen /* we rely on errno not changing. it shouldn't. */
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen i_assert(errno == old_errno);
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen#endif
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen va_end(args2);
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen return tmp;
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen}
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainenchar *p_strdup_vprintf(pool_t pool, const char *format, va_list args)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen{
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen char *tmp, *buf;
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen unsigned int size;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen tmp = t_noalloc_strdup_vprintf(format, args, &size);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen if (pool->datastack_pool) {
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen t_buffer_alloc(size);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen return tmp;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen } else {
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen buf = p_malloc(pool, size);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen memcpy(buf, tmp, size - 1);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen return buf;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen }
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen}
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainenchar *vstrconcat(const char *str1, va_list args, size_t *ret_len)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen{
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen const char *str;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen char *temp;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen size_t bufsize, i, len;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen if (str1 == NULL)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen return NULL;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen str = str1;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen bufsize = STRCONCAT_BUFSIZE;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen temp = t_buffer_get(bufsize);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen i = 0;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen do {
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen len = strlen(str);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen if (i + len >= bufsize) {
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen /* need more memory */
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen bufsize = nearest_power(i + len + 1);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen temp = t_buffer_reget(temp, bufsize);
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen }
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen memcpy(temp + i, str, len); i += len;
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen /* next string */
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen str = va_arg(args, const char *);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen } while (str != NULL);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen i_assert(i < bufsize);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen temp[i++] = '\0';
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen *ret_len = i;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen return temp;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen}
46631c1d903c409444b1b1c4a1d41a033c09ee37Timo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainenchar *p_strconcat(pool_t pool, const char *str1, ...)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen{
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen va_list args;
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen char *temp, *ret;
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen size_t len;
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen va_start(args, str1);
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen if (pool->datastack_pool) {
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen ret = vstrconcat(str1, args, &len);
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen if (ret != NULL)
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen t_buffer_alloc(len);
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen } else {
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen T_BEGIN {
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen temp = vstrconcat(str1, args, &len);
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen if (temp == NULL)
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen ret = NULL;
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen else {
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen t_buffer_alloc(len);
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen ret = p_malloc(pool, len);
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen memcpy(ret, temp, len);
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen }
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen } T_END;
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen }
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainen
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainen va_end(args);
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainen return ret;
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainen}
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainen
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainenconst char *t_strdup(const char *str)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen{
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen return p_strdup(unsafe_data_stack_pool, str);
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen}
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainenchar *t_strdup_noconst(const char *str)
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen{
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen return p_strdup(unsafe_data_stack_pool, str);
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen}
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainenconst char *t_strdup_empty(const char *str)
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen{
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen return p_strdup_empty(unsafe_data_stack_pool, str);
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen}
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainenconst char *t_strdup_until(const void *start, const void *end)
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen{
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen return p_strdup_until(unsafe_data_stack_pool, start, end);
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenconst char *t_strndup(const void *str, size_t max_chars)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return p_strndup(unsafe_data_stack_pool, str, max_chars);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainenconst char *t_strdup_printf(const char *format, ...)
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen{
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainen va_list args;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen const char *ret;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen va_start(args, format);
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen ret = p_strdup_vprintf(unsafe_data_stack_pool, format, args);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen va_end(args);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return ret;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainenconst char *t_strdup_vprintf(const char *format, va_list args)
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen{
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen return p_strdup_vprintf(unsafe_data_stack_pool, format, args);
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen}
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainenconst char *t_strconcat(const char *str1, ...)
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen va_list args;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen const char *ret;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen size_t len;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen va_start(args, str1);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen ret = vstrconcat(str1, args, &len);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (ret != NULL)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen t_buffer_alloc(len);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen va_end(args);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return ret;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainenconst char *t_strcut(const char *str, char cutchar)
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen{
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen const char *p;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen for (p = str; *p != '\0'; p++) {
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen if (*p == cutchar)
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen return t_strdup_until(str, p);
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen }
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
e44028b5df7045dd9e7f324175e73e3ff490cb5dTimo Sirainen return str;
d28179fd78550a58be44dcb1e3e830ab7d33172dTimo Sirainen}
d28179fd78550a58be44dcb1e3e830ab7d33172dTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainenconst char *t_str_replace(const char *str, char from, char to)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen{
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen char *out;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen unsigned int i, len;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
b3f4c31f1533e25380f49f77d5bb1251bf43db2aTimo Sirainen if (strchr(str, from) == NULL)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen return str;
bace943c67e6cd14ce6c994f533d82a3caad5bf1Timo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen len = strlen(str);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen out = t_malloc(len + 1);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen for (i = 0; i < len; i++) {
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen if (str[i] == from)
c096257fbdaf4b9fcf8eb97aae94afdbb4e71ed4Timo Sirainen out[i] = to;
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen else
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen out[i] = str[i];
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen }
e44028b5df7045dd9e7f324175e73e3ff490cb5dTimo Sirainen out[i] = '\0';
e44028b5df7045dd9e7f324175e73e3ff490cb5dTimo Sirainen return out;
e44028b5df7045dd9e7f324175e73e3ff490cb5dTimo Sirainen}
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
bace943c67e6cd14ce6c994f533d82a3caad5bf1Timo Sirainenint i_strocpy(char *dest, const char *src, size_t dstsize)
bace943c67e6cd14ce6c994f533d82a3caad5bf1Timo Sirainen{
c096257fbdaf4b9fcf8eb97aae94afdbb4e71ed4Timo Sirainen if (dstsize == 0)
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen return -1;
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen while (*src != '\0' && dstsize > 1) {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen *dest++ = *src++;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen dstsize--;
c096257fbdaf4b9fcf8eb97aae94afdbb4e71ed4Timo Sirainen }
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen *dest = '\0';
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen return *src == '\0' ? 0 : -1;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenchar *str_ucase(char *str)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen char *p;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
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));
}
#if 0 /* FIXME: wait for v2.3 due to a collision with pigeonhole */
const char *t_str_trim(const char *str, const char *chars)
{
const char *p, *pend, *begin;
pend = str + strlen(str);
if (pend == str)
return "";
p = str;
while (p < pend && strchr(chars, *p) != NULL)
p++;
begin = p;
p = pend - 1;
while (p > begin && strchr(chars, *p) != NULL)
p--;
if (p <= begin)
return "";
return t_strdup_until(begin, p+1);
}
#endif
const char *str_ltrim(const char *str, const char *chars)
{
const char *p;
if (*str == '\0')
return "";
p = str;
while (*p != '\0' && strchr(chars, *p) != NULL)
p++;
return p;
}
const char *t_str_ltrim(const char *str, const char *chars)
{
return t_strdup(str_ltrim(str, chars));
}
const char *t_str_rtrim(const char *str, const char *chars)
{
const char *p, *pend;
pend = str + strlen(str);
if (pend == str)
return "";
p = pend - 1;
while (p > str && strchr(chars, *p) != NULL)
p--;
if (p <= str)
return "";
return t_strdup_until(str, p+1);
}
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 char *key, const char *const *member)
{
return strcmp(key, *member);
}
int i_strcmp_p(const char *const *p1, const char *const *p2)
{
return strcmp(*p1, *p2);
}
int bsearch_strcasecmp(const char *key, const char *const *member)
{
return strcasecmp(key, *member);
}
int i_strcasecmp_p(const char *const *p1, const char *const *p2)
{
return strcasecmp(*p1, *p2);
}
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;
}