lib/util: Clean up includes for time.[ch]
[sfrench/samba-autobuild/.git] / lib / util / substitute.c
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 "includes.h"
25
26 /**
27  * @file
28  * @brief Substitute utilities.
29  **/
30
31 /**
32  Substitute a string for a pattern in another string. Make sure there is
33  enough room!
34
35  This routine looks for pattern in s and replaces it with
36  insert. It may do multiple replacements or just one.
37
38  Any of " ; ' $ or ` in the insert string are replaced with _
39  if len==0 then the string cannot be extended. This is different from the old
40  use of len==0 which was for no length checks to be done.
41 **/
42
43 static void string_sub2(char *s,const char *pattern, const char *insert, size_t len,
44                         bool remove_unsafe_characters, bool replace_once,
45                         bool allow_trailing_dollar)
46 {
47         char *p;
48         ssize_t ls, lp, li, i;
49
50         if (!insert || !pattern || !*pattern || !s)
51                 return;
52
53         ls = (ssize_t)strlen(s);
54         lp = (ssize_t)strlen(pattern);
55         li = (ssize_t)strlen(insert);
56
57         if (len == 0)
58                 len = ls + 1; /* len is number of *bytes* */
59
60         while (lp <= ls && (p = strstr_m(s,pattern))) {
61                 if (ls + (li-lp) >= len) {
62                         DEBUG(0,("ERROR: string overflow by "
63                                 "%d in string_sub(%.50s, %d)\n",
64                                  (int)(ls + (li-lp) - len),
65                                  pattern, (int)len));
66                         break;
67                 }
68                 if (li != lp) {
69                         memmove(p+li,p+lp,strlen(p+lp)+1);
70                 }
71                 for (i=0;i<li;i++) {
72                         switch (insert[i]) {
73                         case '$':
74                                 /* allow a trailing $
75                                  * (as in machine accounts) */
76                                 if (allow_trailing_dollar && (i == li - 1 )) {
77                                         p[i] = insert[i];
78                                         break;
79                                 }
80                         case '`':
81                         case '"':
82                         case '\'':
83                         case ';':
84                         case '%':
85                         case '\r':
86                         case '\n':
87                                 if ( remove_unsafe_characters ) {
88                                         p[i] = '_';
89                                         /* yes this break should be here
90                                          * since we want to fall throw if
91                                          * not replacing unsafe chars */
92                                         break;
93                                 }
94                         default:
95                                 p[i] = insert[i];
96                         }
97                 }
98                 s = p + li;
99                 ls += (li-lp);
100
101                 if (replace_once)
102                         break;
103         }
104 }
105
106 void string_sub_once(char *s, const char *pattern,
107                 const char *insert, size_t len)
108 {
109         string_sub2( s, pattern, insert, len, true, true, false );
110 }
111
112 void string_sub(char *s,const char *pattern, const char *insert, size_t len)
113 {
114         string_sub2( s, pattern, insert, len, true, false, false );
115 }
116
117 /**
118  * Talloc'ed version of string_sub
119  */
120 _PUBLIC_ char *string_sub_talloc(TALLOC_CTX *mem_ctx, const char *s, 
121                                 const char *pattern, const char *insert)
122 {
123         const char *p;
124         char *ret;
125         size_t len, alloc_len;
126
127         if (insert == NULL || pattern == NULL || !*pattern || s == NULL)
128                 return NULL;
129
130         /* determine length needed */
131         len = strlen(s);
132         
133         for (p = strstr(s, pattern); p != NULL; 
134              p = strstr(p+strlen(pattern), pattern)) {
135                 len += strlen(insert) - strlen(pattern);
136         }
137
138         alloc_len = MAX(len, strlen(s))+1;
139         ret = talloc_array(mem_ctx, char, alloc_len);
140         if (ret == NULL)
141                 return NULL;
142         strncpy(ret, s, alloc_len);
143         string_sub(ret, pattern, insert, alloc_len);
144
145         ret = talloc_realloc(mem_ctx, ret, char, len+1);
146         if (ret == NULL)
147                 return NULL;
148
149         SMB_ASSERT(ret[len] == '\0');
150
151         talloc_set_name_const(ret, ret);
152
153         return ret;
154 }
155
156 /**
157  Similar to string_sub() but allows for any character to be substituted. 
158  Use with caution!
159  if len==0 then the string cannot be extended. This is different from the old
160  use of len==0 which was for no length checks to be done.
161 **/
162
163 _PUBLIC_ void all_string_sub(char *s,const char *pattern,const char *insert, size_t len)
164 {
165         char *p;
166         ssize_t ls,lp,li;
167
168         if (!insert || !pattern || !s)
169                 return;
170
171         ls = (ssize_t)strlen(s);
172         lp = (ssize_t)strlen(pattern);
173         li = (ssize_t)strlen(insert);
174
175         if (!*pattern)
176                 return;
177
178         if (len == 0)
179                 len = ls + 1; /* len is number of *bytes* */
180
181         while (lp <= ls && (p = strstr_m(s,pattern))) {
182                 if (ls + (li-lp) >= len) {
183                         DEBUG(0,("ERROR: string overflow by "
184                                 "%d in all_string_sub(%.50s, %d)\n",
185                                  (int)(ls + (li-lp) - len),
186                                  pattern, (int)len));
187                         break;
188                 }
189                 if (li != lp) {
190                         memmove(p+li,p+lp,strlen(p+lp)+1);
191                 }
192                 memcpy(p, insert, li);
193                 s = p + li;
194                 ls += (li-lp);
195         }
196 }