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