Coverage Report

Created: 2026-05-16 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dovecot/src/lib/str.c
Line
Count
Source
1
/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
2
3
#include "lib.h"
4
#include "buffer.h"
5
#include "printf-format-fix.h"
6
#include "unichar.h"
7
#include "str.h"
8
9
#include <stdio.h>
10
11
string_t *str_new(pool_t pool, size_t initial_size)
12
676k
{
13
  /* never allocate a 0 byte size buffer. this is especially important
14
     when str_c() is called on an empty string from a different stack
15
     frame (see the comment in buffer.c about this). */
16
676k
  return buffer_create_dynamic(pool, I_MAX(initial_size, 1));
17
676k
}
18
19
string_t *str_new_const(pool_t pool, const char *str, size_t len)
20
0
{
21
0
  string_t *ret;
22
23
0
  i_assert(str[len] == '\0');
24
25
0
  ret = p_new(pool, buffer_t, 1);
26
0
  buffer_create_from_const_data(ret, str, len + 1);
27
0
  str_truncate(ret, len);
28
0
  return ret;
29
0
}
30
31
string_t *t_str_new(size_t initial_size)
32
318k
{
33
318k
  return str_new(pool_datastack_create(), initial_size);
34
318k
}
35
36
string_t *t_str_new_const(const char *str, size_t len)
37
0
{
38
0
  return str_new_const(pool_datastack_create(), str, len);
39
0
}
40
41
void str_free(string_t **str)
42
363k
{
43
363k
  if (str == NULL || *str == NULL)
44
5.67k
    return;
45
46
358k
  buffer_free(str);
47
358k
}
48
49
char *str_free_without_data(string_t **str)
50
0
{
51
0
  buffer_nul_terminate(*str);
52
0
  return buffer_free_without_data(str);
53
0
}
54
55
const char *str_c(string_t *str)
56
651k
{
57
651k
  buffer_nul_terminate(str);
58
651k
  return str->data;
59
651k
}
60
61
char *str_c_modifiable(string_t *str)
62
0
{
63
0
  buffer_nul_terminate(str);
64
0
  return buffer_get_modifiable_data(str, NULL);
65
0
}
66
67
bool str_equals(const string_t *str1, const string_t *str2)
68
0
{
69
0
  if (str1->used != str2->used)
70
0
    return FALSE;
71
72
0
  return memcmp(str1->data, str2->data, str1->used) == 0;
73
0
}
74
75
void str_append_max(string_t *str, const char *cstr, size_t max_len)
76
0
{
77
0
  const char *p;
78
0
  size_t len;
79
80
0
  p = memchr(cstr, '\0', max_len);
81
0
  if (p == NULL)
82
0
    len = max_len;
83
0
  else
84
0
    len = p - (const char *)cstr;
85
0
  buffer_append(str, cstr, len);
86
0
}
87
88
void str_printfa(string_t *str, const char *fmt, ...)
89
0
{
90
0
  va_list args;
91
92
0
  va_start(args, fmt);
93
0
  str_vprintfa(str, fmt, args);
94
0
  va_end(args);
95
0
}
96
97
void str_vprintfa(string_t *str, const char *fmt, va_list args)
98
0
{
99
0
#define SNPRINTF_INITIAL_EXTRA_SIZE 128
100
0
  va_list args2;
101
0
  char *tmp;
102
0
  size_t init_size;
103
0
  size_t pos = str->used;
104
0
  int ret, ret2;
105
106
0
  VA_COPY(args2, args);
107
108
  /* the format string is modified only if %m exists in it. it happens
109
     only in error conditions, so don't try to t_push() here since it'll
110
     just slow down the normal code path. */
111
0
  fmt = printf_format_fix_get_len(fmt, &init_size);
112
0
  init_size += SNPRINTF_INITIAL_EXTRA_SIZE;
113
114
  /* @UNSAFE */
115
0
  if (pos+init_size > buffer_get_writable_size(str) &&
116
0
      pos < buffer_get_writable_size(str)) {
117
    /* avoid growing buffer larger if possible. this is also
118
       required if buffer isn't dynamically growing. */
119
0
    init_size = buffer_get_writable_size(str)-pos;
120
0
  }
121
0
  tmp = buffer_get_space_unsafe(str, pos, init_size);
122
0
  ret = vsnprintf(tmp, init_size, fmt, args);
123
0
  i_assert(ret >= 0);
124
125
0
  if ((unsigned int)ret >= init_size) {
126
    /* didn't fit with the first guess. now we know the size,
127
       so try again. */
128
0
    tmp = buffer_get_space_unsafe(str, pos, ret + 1);
129
0
    ret2 = vsnprintf(tmp, ret + 1, fmt, args2);
130
0
    i_assert(ret2 == ret);
131
0
  }
132
0
  va_end(args2);
133
134
  /* drop the unused data, including terminating NUL */
135
0
  buffer_set_used_size(str, pos + ret);
136
0
}
137
138
void str_truncate_utf8(string_t *str, size_t len)
139
0
{
140
0
  size_t size = str_len(str);
141
142
0
  if (size <= len)
143
0
    return;
144
0
  str_truncate(str, uni_utf8_data_truncate(str_data(str), size, len));
145
0
}