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