str.c revision d6af1e63bc7824f1cc5b9b73a1c5f8f8789788d6
181c1aff950e6f8e0556f8974e79d0747845ac0fTimo Sirainen/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "lib.h"
181c1aff950e6f8e0556f8974e79d0747845ac0fTimo Sirainen#include "buffer.h"
6dc4af35c045e10609b13fe80f9cf33f3a06c3ceTimo Sirainen#include "printf-format-fix.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "str.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include <stdio.h>
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstring_t *str_new(pool_t pool, size_t initial_size)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return buffer_create_dynamic(pool, initial_size);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstring_t *str_new_const(pool_t pool, const char *str, size_t len)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen string_t *ret;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen i_assert(str[len] == '\0');
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen ret = buffer_create_const_data(pool, str, len + 1);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen str_truncate(ret, len);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return ret;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainenstring_t *t_str_new(size_t initial_size)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen return str_new(pool_datastack_create(), initial_size);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
cfddb734b85ceaf49451d2f68aaad64a860ca6f6Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenvoid str_free(string_t **str)
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen{
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen buffer_free(str);
9d6dec796909384293006e4289436579089d88d5Timo Sirainen}
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainenstatic void str_add_nul(string_t *str)
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen{
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen const unsigned char *data = str_data(str);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen size_t len = str_len(str);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen size_t alloc = buffer_get_size(str);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen if (len == alloc || data[len] != '\0') {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen buffer_write(str, len, "", 1);
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen /* remove the \0 - we don't want to keep it */
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen buffer_set_used_size(str, len);
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen }
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen}
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
181c1aff950e6f8e0556f8974e79d0747845ac0fTimo Sirainenchar *str_free_without_data(string_t **str)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen{
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen str_add_nul(*str);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen return buffer_free_without_data(str);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen}
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenconst char *str_c(string_t *str)
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen{
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen str_add_nul(str);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen return buffer_get_data(str, NULL);
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen}
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
9d6dec796909384293006e4289436579089d88d5Timo Sirainenconst unsigned char *str_data(const string_t *str)
9d6dec796909384293006e4289436579089d88d5Timo Sirainen{
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen return buffer_get_data(str, NULL);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen}
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenchar *str_c_modifiable(string_t *str)
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen{
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen str_add_nul(str);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen return buffer_get_modifiable_data(str, NULL);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen}
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainensize_t str_len(const string_t *str)
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen{
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen return buffer_get_used_size(str);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen}
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainenbool str_equals(const string_t *str1, const string_t *str2)
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen{
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen if (str1->used != str2->used)
9d6dec796909384293006e4289436579089d88d5Timo Sirainen return FALSE;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen return memcmp(str1->data, str2->data, str1->used) == 0;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen}
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainenvoid str_append(string_t *str, const char *cstr)
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen{
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen buffer_append(str, cstr, strlen(cstr));
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen}
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainenvoid str_append_n(string_t *str, const void *cstr, size_t max_len)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen size_t len;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen len = 0;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen while (len < max_len && ((const char *)cstr)[len] != '\0')
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen len++;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen buffer_append(str, cstr, len);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen}
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainenvoid str_append_c(string_t *str, unsigned char chr)
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen{
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen buffer_append_c(str, chr);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen}
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainenvoid str_append_str(string_t *dest, const string_t *src)
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen{
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen const char *cstr;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen size_t len;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen cstr = buffer_get_data(src, &len);
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen buffer_append(dest, cstr, len);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen}
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainenvoid str_printfa(string_t *str, const char *fmt, ...)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen va_list args;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen va_start(args, fmt);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen str_vprintfa(str, fmt, args);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen va_end(args);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen}
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenvoid str_vprintfa(string_t *str, const char *fmt, va_list args)
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen{
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen#define SNPRINTF_INITIAL_EXTRA_SIZE 256
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen va_list args2;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen char *tmp;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen unsigned int init_size;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen size_t pos = str->used;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen int ret, ret2;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen VA_COPY(args2, args);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen /* the format string is modified only if %m exists in it. it happens
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen only in error conditions, so don't try to t_push() here since it'll
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen just slow down the normal code path. */
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen fmt = printf_format_fix_get_len(fmt, &init_size);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen init_size += SNPRINTF_INITIAL_EXTRA_SIZE;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen /* @UNSAFE */
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen tmp = buffer_get_space_unsafe(str, pos, init_size);
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen ret = vsnprintf(tmp, init_size, fmt, args);
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen i_assert(ret >= 0);
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen if ((unsigned int)ret >= init_size) {
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen /* didn't fit with the first guess. now we know the size,
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen so try again. */
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen tmp = buffer_get_space_unsafe(str, pos, ret + 1);
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen ret2 = vsnprintf(tmp, ret + 1, fmt, args2);
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen i_assert(ret2 == ret);
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen }
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen /* drop the unused data, including terminating NUL */
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen buffer_set_used_size(str, pos + ret);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenvoid str_insert(string_t *str, size_t pos, const char *cstr)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen buffer_insert(str, pos, cstr, strlen(cstr));
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenvoid str_delete(string_t *str, size_t pos, size_t len)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen buffer_delete(str, pos, len);
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen}
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenvoid str_truncate(string_t *str, size_t len)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen{
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen buffer_set_used_size(str, len);
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen}
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen