1 /*
2 * Copyright (C) 2002-2012 Free Software Foundation, Inc.
3 * Copyright (C) 2013 Nikos Mavrogiannopoulos
4 *
5 * Author: Nikos Mavrogiannopoulos
6 *
7 * This file is part of ocserv.
8 *
9 * ocserv is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include <config.h>
24 #include <c-ctype.h>
25 #include <string.h>
26 #include <stddef.h>
27 #include <stdlib.h>
28 #include <minmax.h>
29 #include <str.h>
30 #include <main.h>
31 #include "vasprintf.h"
32
trim_trailing_whitespace(char * str)33 void trim_trailing_whitespace(char *str)
34 {
35 unsigned len = strlen(str);
36 char *p;
37
38 if (len > 0) {
39 p = str+len-1;
40 while (p >= str && c_isspace(*p)) {
41 *p = 0;
42 p--;
43 }
44 }
45 }
46
47 #define MEMSUB(x,y) ((ssize_t)((ptrdiff_t)x-(ptrdiff_t)y))
48
str_clear(str_st * str)49 void str_clear(str_st * str)
50 {
51 if (str == NULL || str->allocd == NULL)
52 return;
53 talloc_free(str->allocd);
54
55 str->data = str->allocd = NULL;
56 str->max_length = 0;
57 str->length = 0;
58 }
59
60 #define MIN_CHUNK 64
61 /* This function makes sure there is an additional byte in dest;
62 */
str_append_size(str_st * dest,size_t data_size)63 int str_append_size(str_st * dest, size_t data_size)
64 {
65 size_t tot_len = data_size + dest->length;
66
67 if (data_size == 0)
68 return 0;
69
70 if (dest->max_length >= tot_len+1) {
71 size_t unused = MEMSUB(dest->data, dest->allocd);
72
73 if (dest->max_length - unused <= tot_len) {
74 if (dest->length && dest->data)
75 memmove(dest->allocd, dest->data,
76 dest->length);
77
78 dest->data = dest->allocd;
79 }
80
81 return tot_len;
82 } else {
83 size_t unused = MEMSUB(dest->data, dest->allocd);
84 size_t new_len =
85 MAX(data_size, MIN_CHUNK) + MAX(dest->max_length,
86 MIN_CHUNK);
87
88 dest->allocd = talloc_realloc_size(dest->pool, dest->allocd, new_len+1);
89 if (dest->allocd == NULL)
90 return ERR_MEM;
91 dest->max_length = new_len;
92 dest->data = dest->allocd + unused;
93
94 if (dest->length && dest->data)
95 memmove(dest->allocd, dest->data, dest->length);
96 dest->data = dest->allocd;
97
98 return tot_len;
99 }
100 }
101
102 /* This function always null terminates the string in dest.
103 */
str_append_data(str_st * dest,const void * data,size_t data_size)104 int str_append_data(str_st * dest, const void *data, size_t data_size)
105 {
106 int ret;
107
108 ret = str_append_size(dest, data_size+1);
109 if (ret < 0)
110 return ret;
111
112 memcpy(&dest->data[dest->length], data, data_size);
113 dest->length = data_size + dest->length;
114 dest->data[dest->length] = 0;
115
116 return 0;
117 }
118
str_append_data_prefix1(str_st * dest,const void * data,size_t data_size)119 int str_append_data_prefix1(str_st * dest, const void *data, size_t data_size)
120 {
121 int ret;
122 uint8_t prefix = data_size;
123
124 ret = str_append_data(dest, &prefix, 1);
125 if (ret >= 0) {
126 ret = str_append_data(dest, data, data_size);
127 }
128
129 return ret;
130 }
131
132 /* Appends the provided string. The null termination byte is appended
133 * but not included in length.
134 */
str_append_str(str_st * dest,const char * src)135 int str_append_str(str_st * dest, const char *src)
136 {
137 int ret;
138
139 if (src == NULL)
140 return -1;
141
142 ret = str_append_data(dest, src, strlen(src) + 1);
143 if (ret >= 0)
144 dest->length--;
145
146 return ret;
147 }
148
149 int
str_append_printf(str_st * dest,const char * fmt,...)150 str_append_printf(str_st *dest, const char *fmt, ...)
151 {
152 va_list args;
153 int len;
154 char *str = NULL;
155
156 va_start(args, fmt);
157 len = vasprintf(&str, fmt, args);
158 va_end(args);
159
160 if (len < 0 || !str)
161 return -1;
162
163 len = str_append_str(dest, str);
164
165 free(str);
166
167 return len;
168 }
169
str_replace_str(str_st * str,const str_rep_tab * tab)170 int str_replace_str(str_st *str, const str_rep_tab *tab)
171 {
172 uint8_t *p;
173 const str_rep_tab *ptab;
174 unsigned length;
175 char *final;
176 unsigned final_len;
177 int ret;
178 size_t pos;
179
180 p = str->data;
181 pos = 0;
182 do {
183 p = memchr(p, '%', str->length - pos);
184 if (p == NULL)
185 break;
186
187 pos = (ptrdiff_t)(p-str->data);
188
189 length = str->length - pos;
190
191 ptab = tab;
192 do {
193 if (length >= ptab->pattern_length &&
194 memcmp(ptab->pattern, p, ptab->pattern_length) == 0) {
195 /* replace */
196 final_len = length - ptab->pattern_length;
197 final = talloc_memdup(str->allocd, p+ptab->pattern_length, final_len);
198 if (final == NULL)
199 return -1;
200
201 str->length -= final_len + ptab->pattern_length;
202 if (ptab->rep_val)
203 ret = str_append_str(str, ptab->rep_val);
204 else {
205 char *t = ptab->rep_func(str->pool, ptab->rep_func_input);
206 ret = str_append_str(str, t);
207 talloc_free(t);
208 }
209 if (ret < 0) {
210 talloc_free(final);
211 return ret;
212 }
213
214 ret = str_append_data(str, final, final_len);
215 talloc_free(final);
216 if (ret < 0) {
217 return ret;
218 }
219 break;
220 }
221 ptab++;
222
223 if (ptab->pattern == NULL) {
224 /* not found */
225 return -1;
226 }
227 } while(1);
228
229 p = &str->data[pos];
230 } while(pos < str->length);
231
232 return 0;
233 }
234
235