1 /*
2 * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers.
3 * All rights reserved.
4 *
5 * By using this file, you agree to the terms and conditions set
6 * forth in the LICENSE file which can be found at the top level of
7 * the sendmail distribution.
8 *
9 */
10
11 #pragma ident "%Z%%M% %I% %E% SMI"
12
13 #include <sm/gen.h>
14 SM_RCSID("@(#)$Id: strl.c,v 1.31 2002/01/20 01:41:25 gshapiro Exp $")
15 #include <sm/config.h>
16 #include <sm/string.h>
17
18 /*
19 ** Notice: this file is used by libmilter. Please try to avoid
20 ** using libsm specific functions.
21 */
22
23 /*
24 ** XXX the type of the length parameter has been changed
25 ** from size_t to ssize_t to avoid theoretical problems with negative
26 ** numbers passed into these functions.
27 ** The real solution to this problem is to make sure that this doesn't
28 ** happen, but for now we'll use this workaround.
29 */
30
31 /*
32 ** SM_STRLCPY -- size bounded string copy
33 **
34 ** This is a bounds-checking variant of strcpy.
35 ** If size > 0, copy up to size-1 characters from the nul terminated
36 ** string src to dst, nul terminating the result. If size == 0,
37 ** the dst buffer is not modified.
38 ** Additional note: this function has been "tuned" to run fast and tested
39 ** as such (versus versions in some OS's libc).
40 **
41 ** The result is strlen(src). You can detect truncation (not all
42 ** of the characters in the source string were copied) using the
43 ** following idiom:
44 **
45 ** char *s, buf[BUFSIZ];
46 ** ...
47 ** if (sm_strlcpy(buf, s, sizeof(buf)) >= sizeof(buf))
48 ** goto overflow;
49 **
50 ** Parameters:
51 ** dst -- destination buffer
52 ** src -- source string
53 ** size -- size of destination buffer
54 **
55 ** Returns:
56 ** strlen(src)
57 */
58
59 size_t
60 sm_strlcpy(dst, src, size)
61 register char *dst;
62 register const char *src;
63 ssize_t size;
64 {
65 register ssize_t i;
66
67 if (size-- <= 0)
68 return strlen(src);
69 for (i = 0; i < size && (dst[i] = src[i]) != 0; i++)
70 continue;
71 dst[i] = '\0';
72 if (src[i] == '\0')
73 return i;
74 else
75 return i + strlen(src + i);
76 }
77
78 /*
79 ** SM_STRLCAT -- size bounded string concatenation
80 **
81 ** This is a bounds-checking variant of strcat.
82 ** If strlen(dst) < size, then append at most size - strlen(dst) - 1
83 ** characters from the source string to the destination string,
84 ** nul terminating the result. Otherwise, dst is not modified.
85 **
86 ** The result is the initial length of dst + the length of src.
87 ** You can detect overflow (not all of the characters in the
88 ** source string were copied) using the following idiom:
89 **
90 ** char *s, buf[BUFSIZ];
91 ** ...
92 ** if (sm_strlcat(buf, s, sizeof(buf)) >= sizeof(buf))
93 ** goto overflow;
94 **
95 ** Parameters:
96 ** dst -- nul-terminated destination string buffer
97 ** src -- nul-terminated source string
98 ** size -- size of destination buffer
99 **
100 ** Returns:
101 ** total length of the string tried to create
102 ** (= initial length of dst + length of src)
103 */
104
105 size_t
sm_strlcat(dst,src,size)106 sm_strlcat(dst, src, size)
107 register char *dst;
108 register const char *src;
109 ssize_t size;
110 {
111 register ssize_t i, j, o;
112
113 o = strlen(dst);
114 if (size < o + 1)
115 return o + strlen(src);
116 size -= o + 1;
117 for (i = 0, j = o; i < size && (dst[j] = src[i]) != 0; i++, j++)
118 continue;
119 dst[j] = '\0';
120 if (src[i] == '\0')
121 return j;
122 else
123 return j + strlen(src + i);
124 }
125 /*
126 ** SM_STRLCAT2 -- append two strings to dst obeying length and
127 ** '\0' terminate it
128 **
129 ** strlcat2 will append at most len - strlen(dst) - 1 chars.
130 ** terminates with '\0' if len > 0
131 ** dst = dst "+" src1 "+" src2
132 ** use this instead of sm_strlcat(dst,src1); sm_strlcat(dst,src2);
133 ** for better speed.
134 **
135 ** Parameters:
136 ** dst -- "destination" string.
137 ** src1 -- "from" string 1.
138 ** src2 -- "from" string 2.
139 ** len -- max. length of "destination" string.
140 **
141 ** Returns:
142 ** total length of the string tried to create
143 ** (= initial length of dst + length of src)
144 ** if this is greater than len then an overflow would have
145 ** occurred.
146 **
147 */
148
149 size_t
sm_strlcat2(dst,src1,src2,len)150 sm_strlcat2(dst, src1, src2, len)
151 register char *dst;
152 register const char *src1;
153 register const char *src2;
154 ssize_t len;
155 {
156 register ssize_t i, j, o;
157
158 /* current size of dst */
159 o = strlen(dst);
160
161 /* max. size is less than current? */
162 if (len < o + 1)
163 return o + strlen(src1) + strlen(src2);
164
165 len -= o + 1; /* space left in dst */
166
167 /* copy the first string; i: index in src1; j: index in dst */
168 for (i = 0, j = o; i < len && (dst[j] = src1[i]) != 0; i++, j++)
169 continue;
170
171 /* src1: end reached? */
172 if (src1[i] != '\0')
173 {
174 /* no: terminate dst; there is space since i < len */
175 dst[j] = '\0';
176 return j + strlen(src1 + i) + strlen(src2);
177 }
178
179 len -= i; /* space left in dst */
180
181 /* copy the second string; i: index in src2; j: index in dst */
182 for (i = 0; i < len && (dst[j] = src2[i]) != 0; i++, j++)
183 continue;
184 dst[j] = '\0'; /* terminate dst; there is space since i < len */
185 if (src2[i] == '\0')
186 return j;
187 else
188 return j + strlen(src2 + i);
189 }
190
191 /*
192 ** SM_STRLCPYN -- concatenate n strings and assign the result to dst
193 ** while obeying length and '\0' terminate it
194 **
195 ** dst = src1 "+" src2 "+" ...
196 ** use this instead of sm_snprintf() for string values
197 ** and repeated sm_strlc*() calls for better speed.
198 **
199 ** Parameters:
200 ** dst -- "destination" string.
201 ** len -- max. length of "destination" string.
202 ** n -- number of strings
203 ** strings...
204 **
205 ** Returns:
206 ** total length of the string tried to create
207 ** (= initial length of dst + length of src)
208 ** if this is greater than len then an overflow would have
209 ** occurred.
210 */
211
212 size_t
213 #ifdef __STDC__
sm_strlcpyn(char * dst,ssize_t len,int n,...)214 sm_strlcpyn(char *dst, ssize_t len, int n, ...)
215 #else /* __STDC__ */
216 sm_strlcpyn(dst, len, n, va_alist)
217 register char *dst;
218 ssize_t len;
219 int n;
220 va_dcl
221 #endif /* __STDC__ */
222 {
223 register ssize_t i, j;
224 char *str;
225 SM_VA_LOCAL_DECL
226
227 SM_VA_START(ap, n);
228
229 if (len-- <= 0) /* This allows space for the terminating '\0' */
230 {
231 i = 0;
232 while (n-- > 0)
233 i += strlen(SM_VA_ARG(ap, char *));
234 SM_VA_END(ap);
235 return i;
236 }
237
238 j = 0; /* index in dst */
239
240 /* loop through all source strings */
241 while (n-- > 0)
242 {
243 str = SM_VA_ARG(ap, char *);
244
245 /* copy string; i: index in str; j: index in dst */
246 for (i = 0; j < len && (dst[j] = str[i]) != 0; i++, j++)
247 continue;
248
249 /* str: end reached? */
250 if (str[i] != '\0')
251 {
252 /* no: terminate dst; there is space since j < len */
253 dst[j] = '\0';
254 j += strlen(str + i);
255 while (n-- > 0)
256 j += strlen(SM_VA_ARG(ap, char *));
257 SM_VA_END(ap);
258 return j;
259 }
260 }
261 SM_VA_END(ap);
262
263 dst[j] = '\0'; /* terminate dst; there is space since j < len */
264 return j;
265 }
266
267 #if 0
268 /*
269 ** SM_STRLAPP -- append string if it fits into buffer.
270 **
271 ** If size > 0, copy up to size-1 characters from the nul terminated
272 ** string src to dst, nul terminating the result. If size == 0,
273 ** the dst buffer is not modified.
274 **
275 ** This routine is useful for appending strings in a loop, e.g, instead of
276 ** s = buf;
277 ** for (ptr, ptr != NULL, ptr = next->ptr)
278 ** {
279 ** (void) sm_strlcpy(s, ptr->string, sizeof buf - (s - buf));
280 ** s += strlen(s);
281 ** }
282 ** replace the loop body with:
283 ** if (!sm_strlapp(*s, ptr->string, sizeof buf - (s - buf)))
284 ** break;
285 ** it's faster...
286 **
287 ** XXX interface isn't completely clear (yet), hence this code is
288 ** not available.
289 **
290 **
291 ** Parameters:
292 ** dst -- (pointer to) destination buffer
293 ** src -- source string
294 ** size -- size of destination buffer
295 **
296 ** Returns:
297 ** true if strlen(src) < size
298 **
299 ** Side Effects:
300 ** modifies dst if append succeeds (enough space).
301 */
302
303 bool
304 sm_strlapp(dst, src, size)
305 register char **dst;
306 register const char *src;
307 ssize_t size;
308 {
309 register size_t i;
310
311 if (size-- <= 0)
312 return false;
313 for (i = 0; i < size && ((*dst)[i] = src[i]) != '\0'; i++)
314 continue;
315 (*dst)[i] = '\0';
316 if (src[i] == '\0')
317 {
318 *dst += i;
319 return true;
320 }
321
322 /* undo */
323 (*dst)[0] = '\0';
324 return false;
325 }
326 #endif /* 0 */
327