/src/samba/lib/util/substitute.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | Samba utility functions |
4 | | |
5 | | Copyright (C) Andrew Tridgell 1992-2001 |
6 | | Copyright (C) Simo Sorce 2001-2002 |
7 | | Copyright (C) Martin Pool 2003 |
8 | | Copyright (C) James Peach 2005 |
9 | | |
10 | | This program is free software; you can redistribute it and/or modify |
11 | | it under the terms of the GNU General Public License as published by |
12 | | the Free Software Foundation; either version 3 of the License, or |
13 | | (at your option) any later version. |
14 | | |
15 | | This program is distributed in the hope that it will be useful, |
16 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | | GNU General Public License for more details. |
19 | | |
20 | | You should have received a copy of the GNU General Public License |
21 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
22 | | */ |
23 | | |
24 | | #include "replace.h" |
25 | | #include "debug.h" |
26 | | #ifndef SAMBA_UTIL_CORE_ONLY |
27 | | #include "charset/charset.h" |
28 | | #else |
29 | | #include "charset_compat.h" |
30 | | #endif |
31 | | #include "substitute.h" |
32 | | |
33 | | /** |
34 | | * @file |
35 | | * @brief Substitute utilities. |
36 | | **/ |
37 | | |
38 | | /** |
39 | | Substitute a string for a pattern in another string. Make sure there is |
40 | | enough room! |
41 | | |
42 | | This routine looks for pattern in s and replaces it with |
43 | | insert. It may do multiple replacements or just one. |
44 | | |
45 | | Any of " ; ' $ or ` in the insert string are replaced with _ |
46 | | if len==0 then the string cannot be extended. This is different from the old |
47 | | use of len==0 which was for no length checks to be done. |
48 | | **/ |
49 | | |
50 | | static void string_sub2(char *s,const char *pattern, const char *insert, size_t len, |
51 | | bool remove_unsafe_characters, bool replace_once, |
52 | | bool allow_trailing_dollar) |
53 | 2.10k | { |
54 | 2.10k | char *p; |
55 | 2.10k | size_t ls, lp, li, i; |
56 | | |
57 | 2.10k | if (!insert || !pattern || !*pattern || !s) |
58 | 0 | return; |
59 | | |
60 | 2.10k | ls = strlen(s); |
61 | 2.10k | lp = strlen(pattern); |
62 | 2.10k | li = strlen(insert); |
63 | | |
64 | 2.10k | if (len == 0) |
65 | 2.10k | len = ls + 1; /* len is number of *bytes* */ |
66 | | |
67 | 23.4k | while (lp <= ls && (p = strstr_m(s,pattern))) { |
68 | 21.3k | if (ls + li - lp >= len) { |
69 | 0 | DBG_ERR("ERROR: string overflow by " |
70 | 0 | "%zu in string_sub(%.50s, %zu)\n", |
71 | 0 | ls + li - lp + 1 - len, |
72 | 0 | pattern, |
73 | 0 | len); |
74 | 0 | break; |
75 | 0 | } |
76 | 21.3k | if (li != lp) { |
77 | 5.72k | memmove(p+li,p+lp,strlen(p+lp)+1); |
78 | 5.72k | } |
79 | 39.9k | for (i=0;i<li;i++) { |
80 | 18.5k | switch (insert[i]) { |
81 | 0 | case '$': |
82 | | /* allow a trailing $ |
83 | | * (as in machine accounts) */ |
84 | 0 | if (allow_trailing_dollar && (i == li - 1 )) { |
85 | 0 | p[i] = insert[i]; |
86 | 0 | break; |
87 | 0 | } |
88 | 0 | FALL_THROUGH; |
89 | 0 | case '`': |
90 | 0 | case '"': |
91 | 0 | case '\'': |
92 | 0 | case ';': |
93 | 0 | case '%': |
94 | 0 | case '\r': |
95 | 0 | case '\n': |
96 | 0 | if ( remove_unsafe_characters ) { |
97 | 0 | p[i] = '_'; |
98 | | /* yes this break should be here |
99 | | * since we want to fall throw if |
100 | | * not replacing unsafe chars */ |
101 | 0 | break; |
102 | 0 | } |
103 | 0 | FALL_THROUGH; |
104 | 18.5k | default: |
105 | 18.5k | p[i] = insert[i]; |
106 | 18.5k | } |
107 | 18.5k | } |
108 | 21.3k | s = p + li; |
109 | 21.3k | ls = ls + li - lp; |
110 | | |
111 | 21.3k | if (replace_once) |
112 | 0 | break; |
113 | 21.3k | } |
114 | 2.10k | } |
115 | | |
116 | | void string_sub(char *s,const char *pattern, const char *insert, size_t len) |
117 | 2.10k | { |
118 | 2.10k | string_sub2( s, pattern, insert, len, true, false, false ); |
119 | 2.10k | } |
120 | | |
121 | | /** |
122 | | Similar to string_sub() but allows for any character to be substituted. |
123 | | Use with caution! |
124 | | if len==0 then the string cannot be extended. This is different from the old |
125 | | use of len==0 which was for no length checks to be done. |
126 | | **/ |
127 | | |
128 | | _PUBLIC_ void all_string_sub(char *s,const char *pattern,const char *insert, size_t len) |
129 | 1.69k | { |
130 | 1.69k | char *p; |
131 | 1.69k | size_t ls,lp,li; |
132 | | |
133 | 1.69k | if (!insert || !pattern || !s) |
134 | 0 | return; |
135 | | |
136 | 1.69k | ls = strlen(s); |
137 | 1.69k | lp = strlen(pattern); |
138 | 1.69k | li = strlen(insert); |
139 | | |
140 | 1.69k | if (!*pattern) |
141 | 0 | return; |
142 | | |
143 | 1.69k | if (len == 0) |
144 | 1.69k | len = ls + 1; /* len is number of *bytes* */ |
145 | | |
146 | 20.4k | while (lp <= ls && (p = strstr_m(s,pattern))) { |
147 | 18.7k | if (ls + li - lp >= len) { |
148 | 0 | DBG_ERR("ERROR: string overflow by " |
149 | 0 | "%zu in all_string_sub(%.50s, %zu)\n", |
150 | 0 | ls + li - lp + 1 - len, |
151 | 0 | pattern, |
152 | 0 | len); |
153 | 0 | break; |
154 | 0 | } |
155 | 18.7k | if (li != lp) { |
156 | 18.1k | memmove(p+li,p+lp,strlen(p+lp)+1); |
157 | 18.1k | } |
158 | 18.7k | memcpy(p, insert, li); |
159 | 18.7k | s = p + li; |
160 | 18.7k | ls = ls + li - lp; |
161 | 18.7k | } |
162 | 1.69k | } |
163 | | |
164 | | /* |
165 | | * Internal guts of talloc_string_sub and talloc_all_string_sub. |
166 | | * talloc version of string_sub2. |
167 | | */ |
168 | | |
169 | | char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src, |
170 | | const char *pattern, |
171 | | const char *insert, |
172 | | bool remove_unsafe_characters, |
173 | | bool replace_once, |
174 | | bool allow_trailing_dollar) |
175 | 0 | { |
176 | 0 | char *p, *in; |
177 | 0 | char *s; |
178 | 0 | char *string; |
179 | 0 | ssize_t ls,lp,li,ld, i; |
180 | |
|
181 | 0 | if (!insert || !pattern || !*pattern || !src) { |
182 | 0 | return NULL; |
183 | 0 | } |
184 | | |
185 | 0 | string = talloc_strdup(mem_ctx, src); |
186 | 0 | if (string == NULL) { |
187 | 0 | DEBUG(0, ("talloc_string_sub2: " |
188 | 0 | "talloc_strdup failed\n")); |
189 | 0 | return NULL; |
190 | 0 | } |
191 | | |
192 | 0 | s = string; |
193 | |
|
194 | 0 | in = talloc_strdup(mem_ctx, insert); |
195 | 0 | if (!in) { |
196 | 0 | DEBUG(0, ("talloc_string_sub2: ENOMEM\n")); |
197 | 0 | talloc_free(string); |
198 | 0 | return NULL; |
199 | 0 | } |
200 | 0 | ls = (ssize_t)strlen(s); |
201 | 0 | lp = (ssize_t)strlen(pattern); |
202 | 0 | li = (ssize_t)strlen(insert); |
203 | 0 | ld = li - lp; |
204 | |
|
205 | 0 | for (i=0;i<li;i++) { |
206 | 0 | switch (in[i]) { |
207 | 0 | case '$': |
208 | | /* allow a trailing $ |
209 | | * (as in machine accounts) */ |
210 | 0 | if (allow_trailing_dollar && (i == li - 1 )) { |
211 | 0 | break; |
212 | 0 | } |
213 | | |
214 | 0 | FALL_THROUGH; |
215 | 0 | case '`': |
216 | 0 | case '"': |
217 | 0 | case '\'': |
218 | 0 | case ';': |
219 | 0 | case '%': |
220 | 0 | case '\r': |
221 | 0 | case '\n': |
222 | 0 | if (remove_unsafe_characters) { |
223 | 0 | in[i] = '_'; |
224 | 0 | break; |
225 | 0 | } |
226 | | |
227 | 0 | FALL_THROUGH; |
228 | 0 | default: |
229 | | /* ok */ |
230 | 0 | break; |
231 | 0 | } |
232 | 0 | } |
233 | | |
234 | 0 | while ((p = strstr_m(s,pattern))) { |
235 | 0 | if (ld > 0) { |
236 | 0 | int offset = PTR_DIFF(s,string); |
237 | 0 | string = (char *)talloc_realloc_size(mem_ctx, string, |
238 | 0 | ls + ld + 1); |
239 | 0 | if (!string) { |
240 | 0 | DEBUG(0, ("talloc_string_sub: out of " |
241 | 0 | "memory!\n")); |
242 | 0 | TALLOC_FREE(in); |
243 | 0 | return NULL; |
244 | 0 | } |
245 | 0 | p = string + offset + (p - s); |
246 | 0 | } |
247 | 0 | if (li != lp) { |
248 | 0 | memmove(p+li,p+lp,strlen(p+lp)+1); |
249 | 0 | } |
250 | 0 | memcpy(p, in, li); |
251 | 0 | s = p + li; |
252 | 0 | ls += ld; |
253 | |
|
254 | 0 | if (replace_once) { |
255 | 0 | break; |
256 | 0 | } |
257 | 0 | } |
258 | 0 | TALLOC_FREE(in); |
259 | 0 | return string; |
260 | 0 | } |
261 | | |
262 | | /* Same as string_sub, but returns a talloc'ed string */ |
263 | | |
264 | | char *talloc_string_sub(TALLOC_CTX *mem_ctx, |
265 | | const char *src, |
266 | | const char *pattern, |
267 | | const char *insert) |
268 | 0 | { |
269 | 0 | return talloc_string_sub2(mem_ctx, src, pattern, insert, |
270 | 0 | true, false, false); |
271 | 0 | } |
272 | | |
273 | | char *talloc_all_string_sub(TALLOC_CTX *ctx, |
274 | | const char *src, |
275 | | const char *pattern, |
276 | | const char *insert) |
277 | 0 | { |
278 | 0 | return talloc_string_sub2(ctx, src, pattern, insert, |
279 | 0 | false, false, false); |
280 | 0 | } |