140266059SGregory Neil Shapiro /*
25dd76dd0SGregory Neil Shapiro * Copyright (c) 1999-2002 Proofpoint, Inc. and its suppliers.
340266059SGregory Neil Shapiro * All rights reserved.
440266059SGregory Neil Shapiro *
540266059SGregory Neil Shapiro * By using this file, you agree to the terms and conditions set
640266059SGregory Neil Shapiro * forth in the LICENSE file which can be found at the top level of
740266059SGregory Neil Shapiro * the sendmail distribution.
840266059SGregory Neil Shapiro *
940266059SGregory Neil Shapiro */
1040266059SGregory Neil Shapiro
1140266059SGregory Neil Shapiro #include <sm/gen.h>
12*4313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: strl.c,v 1.32 2013-11-22 20:51:43 ca Exp $")
1340266059SGregory Neil Shapiro #include <sm/config.h>
1440266059SGregory Neil Shapiro #include <sm/string.h>
1540266059SGregory Neil Shapiro
1640266059SGregory Neil Shapiro /*
1740266059SGregory Neil Shapiro ** Notice: this file is used by libmilter. Please try to avoid
1840266059SGregory Neil Shapiro ** using libsm specific functions.
1940266059SGregory Neil Shapiro */
2040266059SGregory Neil Shapiro
2140266059SGregory Neil Shapiro /*
2240266059SGregory Neil Shapiro ** XXX the type of the length parameter has been changed
2340266059SGregory Neil Shapiro ** from size_t to ssize_t to avoid theoretical problems with negative
2440266059SGregory Neil Shapiro ** numbers passed into these functions.
2540266059SGregory Neil Shapiro ** The real solution to this problem is to make sure that this doesn't
2640266059SGregory Neil Shapiro ** happen, but for now we'll use this workaround.
2740266059SGregory Neil Shapiro */
2840266059SGregory Neil Shapiro
2940266059SGregory Neil Shapiro /*
3040266059SGregory Neil Shapiro ** SM_STRLCPY -- size bounded string copy
3140266059SGregory Neil Shapiro **
3240266059SGregory Neil Shapiro ** This is a bounds-checking variant of strcpy.
3340266059SGregory Neil Shapiro ** If size > 0, copy up to size-1 characters from the nul terminated
3440266059SGregory Neil Shapiro ** string src to dst, nul terminating the result. If size == 0,
3540266059SGregory Neil Shapiro ** the dst buffer is not modified.
3640266059SGregory Neil Shapiro ** Additional note: this function has been "tuned" to run fast and tested
3740266059SGregory Neil Shapiro ** as such (versus versions in some OS's libc).
3840266059SGregory Neil Shapiro **
3940266059SGregory Neil Shapiro ** The result is strlen(src). You can detect truncation (not all
4040266059SGregory Neil Shapiro ** of the characters in the source string were copied) using the
4140266059SGregory Neil Shapiro ** following idiom:
4240266059SGregory Neil Shapiro **
4340266059SGregory Neil Shapiro ** char *s, buf[BUFSIZ];
4440266059SGregory Neil Shapiro ** ...
4540266059SGregory Neil Shapiro ** if (sm_strlcpy(buf, s, sizeof(buf)) >= sizeof(buf))
4640266059SGregory Neil Shapiro ** goto overflow;
4740266059SGregory Neil Shapiro **
4840266059SGregory Neil Shapiro ** Parameters:
4940266059SGregory Neil Shapiro ** dst -- destination buffer
5040266059SGregory Neil Shapiro ** src -- source string
5140266059SGregory Neil Shapiro ** size -- size of destination buffer
5240266059SGregory Neil Shapiro **
5340266059SGregory Neil Shapiro ** Returns:
5440266059SGregory Neil Shapiro ** strlen(src)
5540266059SGregory Neil Shapiro */
5640266059SGregory Neil Shapiro
5740266059SGregory Neil Shapiro size_t
5840266059SGregory Neil Shapiro sm_strlcpy(dst, src, size)
5940266059SGregory Neil Shapiro register char *dst;
6040266059SGregory Neil Shapiro register const char *src;
6140266059SGregory Neil Shapiro ssize_t size;
6240266059SGregory Neil Shapiro {
6340266059SGregory Neil Shapiro register ssize_t i;
6440266059SGregory Neil Shapiro
6540266059SGregory Neil Shapiro if (size-- <= 0)
6640266059SGregory Neil Shapiro return strlen(src);
6740266059SGregory Neil Shapiro for (i = 0; i < size && (dst[i] = src[i]) != 0; i++)
6840266059SGregory Neil Shapiro continue;
6940266059SGregory Neil Shapiro dst[i] = '\0';
7040266059SGregory Neil Shapiro if (src[i] == '\0')
7140266059SGregory Neil Shapiro return i;
7240266059SGregory Neil Shapiro else
7340266059SGregory Neil Shapiro return i + strlen(src + i);
7440266059SGregory Neil Shapiro }
7540266059SGregory Neil Shapiro
7640266059SGregory Neil Shapiro /*
7740266059SGregory Neil Shapiro ** SM_STRLCAT -- size bounded string concatenation
7840266059SGregory Neil Shapiro **
7940266059SGregory Neil Shapiro ** This is a bounds-checking variant of strcat.
8040266059SGregory Neil Shapiro ** If strlen(dst) < size, then append at most size - strlen(dst) - 1
8140266059SGregory Neil Shapiro ** characters from the source string to the destination string,
8240266059SGregory Neil Shapiro ** nul terminating the result. Otherwise, dst is not modified.
8340266059SGregory Neil Shapiro **
8440266059SGregory Neil Shapiro ** The result is the initial length of dst + the length of src.
8540266059SGregory Neil Shapiro ** You can detect overflow (not all of the characters in the
8640266059SGregory Neil Shapiro ** source string were copied) using the following idiom:
8740266059SGregory Neil Shapiro **
8840266059SGregory Neil Shapiro ** char *s, buf[BUFSIZ];
8940266059SGregory Neil Shapiro ** ...
9040266059SGregory Neil Shapiro ** if (sm_strlcat(buf, s, sizeof(buf)) >= sizeof(buf))
9140266059SGregory Neil Shapiro ** goto overflow;
9240266059SGregory Neil Shapiro **
9340266059SGregory Neil Shapiro ** Parameters:
9440266059SGregory Neil Shapiro ** dst -- nul-terminated destination string buffer
9540266059SGregory Neil Shapiro ** src -- nul-terminated source string
9640266059SGregory Neil Shapiro ** size -- size of destination buffer
9740266059SGregory Neil Shapiro **
9840266059SGregory Neil Shapiro ** Returns:
9940266059SGregory Neil Shapiro ** total length of the string tried to create
10040266059SGregory Neil Shapiro ** (= initial length of dst + length of src)
10140266059SGregory Neil Shapiro */
10240266059SGregory Neil Shapiro
10340266059SGregory Neil Shapiro size_t
sm_strlcat(dst,src,size)10440266059SGregory Neil Shapiro sm_strlcat(dst, src, size)
10540266059SGregory Neil Shapiro register char *dst;
10640266059SGregory Neil Shapiro register const char *src;
10740266059SGregory Neil Shapiro ssize_t size;
10840266059SGregory Neil Shapiro {
10940266059SGregory Neil Shapiro register ssize_t i, j, o;
11040266059SGregory Neil Shapiro
11140266059SGregory Neil Shapiro o = strlen(dst);
11240266059SGregory Neil Shapiro if (size < o + 1)
11340266059SGregory Neil Shapiro return o + strlen(src);
11440266059SGregory Neil Shapiro size -= o + 1;
11540266059SGregory Neil Shapiro for (i = 0, j = o; i < size && (dst[j] = src[i]) != 0; i++, j++)
11640266059SGregory Neil Shapiro continue;
11740266059SGregory Neil Shapiro dst[j] = '\0';
11840266059SGregory Neil Shapiro if (src[i] == '\0')
11940266059SGregory Neil Shapiro return j;
12040266059SGregory Neil Shapiro else
12140266059SGregory Neil Shapiro return j + strlen(src + i);
12240266059SGregory Neil Shapiro }
12340266059SGregory Neil Shapiro /*
12440266059SGregory Neil Shapiro ** SM_STRLCAT2 -- append two strings to dst obeying length and
12540266059SGregory Neil Shapiro ** '\0' terminate it
12640266059SGregory Neil Shapiro **
12740266059SGregory Neil Shapiro ** strlcat2 will append at most len - strlen(dst) - 1 chars.
12840266059SGregory Neil Shapiro ** terminates with '\0' if len > 0
12940266059SGregory Neil Shapiro ** dst = dst "+" src1 "+" src2
13040266059SGregory Neil Shapiro ** use this instead of sm_strlcat(dst,src1); sm_strlcat(dst,src2);
13140266059SGregory Neil Shapiro ** for better speed.
13240266059SGregory Neil Shapiro **
13340266059SGregory Neil Shapiro ** Parameters:
13440266059SGregory Neil Shapiro ** dst -- "destination" string.
13540266059SGregory Neil Shapiro ** src1 -- "from" string 1.
13640266059SGregory Neil Shapiro ** src2 -- "from" string 2.
13740266059SGregory Neil Shapiro ** len -- max. length of "destination" string.
13840266059SGregory Neil Shapiro **
13940266059SGregory Neil Shapiro ** Returns:
14040266059SGregory Neil Shapiro ** total length of the string tried to create
14140266059SGregory Neil Shapiro ** (= initial length of dst + length of src)
14240266059SGregory Neil Shapiro ** if this is greater than len then an overflow would have
14340266059SGregory Neil Shapiro ** occurred.
14440266059SGregory Neil Shapiro **
14540266059SGregory Neil Shapiro */
14640266059SGregory Neil Shapiro
14740266059SGregory Neil Shapiro size_t
sm_strlcat2(dst,src1,src2,len)14840266059SGregory Neil Shapiro sm_strlcat2(dst, src1, src2, len)
14940266059SGregory Neil Shapiro register char *dst;
15040266059SGregory Neil Shapiro register const char *src1;
15140266059SGregory Neil Shapiro register const char *src2;
15240266059SGregory Neil Shapiro ssize_t len;
15340266059SGregory Neil Shapiro {
15440266059SGregory Neil Shapiro register ssize_t i, j, o;
15540266059SGregory Neil Shapiro
15640266059SGregory Neil Shapiro /* current size of dst */
15740266059SGregory Neil Shapiro o = strlen(dst);
15840266059SGregory Neil Shapiro
15940266059SGregory Neil Shapiro /* max. size is less than current? */
16040266059SGregory Neil Shapiro if (len < o + 1)
16140266059SGregory Neil Shapiro return o + strlen(src1) + strlen(src2);
16240266059SGregory Neil Shapiro
16340266059SGregory Neil Shapiro len -= o + 1; /* space left in dst */
16440266059SGregory Neil Shapiro
16540266059SGregory Neil Shapiro /* copy the first string; i: index in src1; j: index in dst */
16640266059SGregory Neil Shapiro for (i = 0, j = o; i < len && (dst[j] = src1[i]) != 0; i++, j++)
16740266059SGregory Neil Shapiro continue;
16840266059SGregory Neil Shapiro
16940266059SGregory Neil Shapiro /* src1: end reached? */
17040266059SGregory Neil Shapiro if (src1[i] != '\0')
17140266059SGregory Neil Shapiro {
17240266059SGregory Neil Shapiro /* no: terminate dst; there is space since i < len */
17340266059SGregory Neil Shapiro dst[j] = '\0';
17440266059SGregory Neil Shapiro return j + strlen(src1 + i) + strlen(src2);
17540266059SGregory Neil Shapiro }
17640266059SGregory Neil Shapiro
17740266059SGregory Neil Shapiro len -= i; /* space left in dst */
17840266059SGregory Neil Shapiro
17940266059SGregory Neil Shapiro /* copy the second string; i: index in src2; j: index in dst */
18040266059SGregory Neil Shapiro for (i = 0; i < len && (dst[j] = src2[i]) != 0; i++, j++)
18140266059SGregory Neil Shapiro continue;
18240266059SGregory Neil Shapiro dst[j] = '\0'; /* terminate dst; there is space since i < len */
18340266059SGregory Neil Shapiro if (src2[i] == '\0')
18440266059SGregory Neil Shapiro return j;
18540266059SGregory Neil Shapiro else
18640266059SGregory Neil Shapiro return j + strlen(src2 + i);
18740266059SGregory Neil Shapiro }
18840266059SGregory Neil Shapiro
18940266059SGregory Neil Shapiro /*
19040266059SGregory Neil Shapiro ** SM_STRLCPYN -- concatenate n strings and assign the result to dst
19140266059SGregory Neil Shapiro ** while obeying length and '\0' terminate it
19240266059SGregory Neil Shapiro **
19340266059SGregory Neil Shapiro ** dst = src1 "+" src2 "+" ...
19440266059SGregory Neil Shapiro ** use this instead of sm_snprintf() for string values
19540266059SGregory Neil Shapiro ** and repeated sm_strlc*() calls for better speed.
19640266059SGregory Neil Shapiro **
19740266059SGregory Neil Shapiro ** Parameters:
19840266059SGregory Neil Shapiro ** dst -- "destination" string.
19940266059SGregory Neil Shapiro ** len -- max. length of "destination" string.
20040266059SGregory Neil Shapiro ** n -- number of strings
20140266059SGregory Neil Shapiro ** strings...
20240266059SGregory Neil Shapiro **
20340266059SGregory Neil Shapiro ** Returns:
20440266059SGregory Neil Shapiro ** total length of the string tried to create
20540266059SGregory Neil Shapiro ** (= initial length of dst + length of src)
20640266059SGregory Neil Shapiro ** if this is greater than len then an overflow would have
20740266059SGregory Neil Shapiro ** occurred.
20840266059SGregory Neil Shapiro */
20940266059SGregory Neil Shapiro
21040266059SGregory Neil Shapiro size_t
21140266059SGregory Neil Shapiro #ifdef __STDC__
sm_strlcpyn(char * dst,ssize_t len,int n,...)21240266059SGregory Neil Shapiro sm_strlcpyn(char *dst, ssize_t len, int n, ...)
21340266059SGregory Neil Shapiro #else /* __STDC__ */
21440266059SGregory Neil Shapiro sm_strlcpyn(dst, len, n, va_alist)
21540266059SGregory Neil Shapiro register char *dst;
21640266059SGregory Neil Shapiro ssize_t len;
21740266059SGregory Neil Shapiro int n;
21840266059SGregory Neil Shapiro va_dcl
21940266059SGregory Neil Shapiro #endif /* __STDC__ */
22040266059SGregory Neil Shapiro {
22140266059SGregory Neil Shapiro register ssize_t i, j;
22240266059SGregory Neil Shapiro char *str;
22340266059SGregory Neil Shapiro SM_VA_LOCAL_DECL
22440266059SGregory Neil Shapiro
22540266059SGregory Neil Shapiro SM_VA_START(ap, n);
22640266059SGregory Neil Shapiro
22740266059SGregory Neil Shapiro if (len-- <= 0) /* This allows space for the terminating '\0' */
22840266059SGregory Neil Shapiro {
22940266059SGregory Neil Shapiro i = 0;
23040266059SGregory Neil Shapiro while (n-- > 0)
23140266059SGregory Neil Shapiro i += strlen(SM_VA_ARG(ap, char *));
232605302a5SGregory Neil Shapiro SM_VA_END(ap);
23340266059SGregory Neil Shapiro return i;
23440266059SGregory Neil Shapiro }
23540266059SGregory Neil Shapiro
23640266059SGregory Neil Shapiro j = 0; /* index in dst */
23740266059SGregory Neil Shapiro
23840266059SGregory Neil Shapiro /* loop through all source strings */
23940266059SGregory Neil Shapiro while (n-- > 0)
24040266059SGregory Neil Shapiro {
24140266059SGregory Neil Shapiro str = SM_VA_ARG(ap, char *);
24240266059SGregory Neil Shapiro
24340266059SGregory Neil Shapiro /* copy string; i: index in str; j: index in dst */
24440266059SGregory Neil Shapiro for (i = 0; j < len && (dst[j] = str[i]) != 0; i++, j++)
24540266059SGregory Neil Shapiro continue;
24640266059SGregory Neil Shapiro
24740266059SGregory Neil Shapiro /* str: end reached? */
24840266059SGregory Neil Shapiro if (str[i] != '\0')
24940266059SGregory Neil Shapiro {
25040266059SGregory Neil Shapiro /* no: terminate dst; there is space since j < len */
25140266059SGregory Neil Shapiro dst[j] = '\0';
25240266059SGregory Neil Shapiro j += strlen(str + i);
25340266059SGregory Neil Shapiro while (n-- > 0)
25440266059SGregory Neil Shapiro j += strlen(SM_VA_ARG(ap, char *));
255605302a5SGregory Neil Shapiro SM_VA_END(ap);
25640266059SGregory Neil Shapiro return j;
25740266059SGregory Neil Shapiro }
25840266059SGregory Neil Shapiro }
259605302a5SGregory Neil Shapiro SM_VA_END(ap);
26040266059SGregory Neil Shapiro
26140266059SGregory Neil Shapiro dst[j] = '\0'; /* terminate dst; there is space since j < len */
26240266059SGregory Neil Shapiro return j;
26340266059SGregory Neil Shapiro }
26440266059SGregory Neil Shapiro
26540266059SGregory Neil Shapiro #if 0
26640266059SGregory Neil Shapiro /*
26740266059SGregory Neil Shapiro ** SM_STRLAPP -- append string if it fits into buffer.
26840266059SGregory Neil Shapiro **
26940266059SGregory Neil Shapiro ** If size > 0, copy up to size-1 characters from the nul terminated
27040266059SGregory Neil Shapiro ** string src to dst, nul terminating the result. If size == 0,
27140266059SGregory Neil Shapiro ** the dst buffer is not modified.
27240266059SGregory Neil Shapiro **
27340266059SGregory Neil Shapiro ** This routine is useful for appending strings in a loop, e.g, instead of
27440266059SGregory Neil Shapiro ** s = buf;
27540266059SGregory Neil Shapiro ** for (ptr, ptr != NULL, ptr = next->ptr)
27640266059SGregory Neil Shapiro ** {
27740266059SGregory Neil Shapiro ** (void) sm_strlcpy(s, ptr->string, sizeof buf - (s - buf));
27840266059SGregory Neil Shapiro ** s += strlen(s);
27940266059SGregory Neil Shapiro ** }
28040266059SGregory Neil Shapiro ** replace the loop body with:
28140266059SGregory Neil Shapiro ** if (!sm_strlapp(*s, ptr->string, sizeof buf - (s - buf)))
28240266059SGregory Neil Shapiro ** break;
28340266059SGregory Neil Shapiro ** it's faster...
28440266059SGregory Neil Shapiro **
28540266059SGregory Neil Shapiro ** XXX interface isn't completely clear (yet), hence this code is
28640266059SGregory Neil Shapiro ** not available.
28740266059SGregory Neil Shapiro **
28840266059SGregory Neil Shapiro **
28940266059SGregory Neil Shapiro ** Parameters:
29040266059SGregory Neil Shapiro ** dst -- (pointer to) destination buffer
29140266059SGregory Neil Shapiro ** src -- source string
29240266059SGregory Neil Shapiro ** size -- size of destination buffer
29340266059SGregory Neil Shapiro **
29440266059SGregory Neil Shapiro ** Returns:
29540266059SGregory Neil Shapiro ** true if strlen(src) < size
29640266059SGregory Neil Shapiro **
29740266059SGregory Neil Shapiro ** Side Effects:
29840266059SGregory Neil Shapiro ** modifies dst if append succeeds (enough space).
29940266059SGregory Neil Shapiro */
30040266059SGregory Neil Shapiro
30140266059SGregory Neil Shapiro bool
30240266059SGregory Neil Shapiro sm_strlapp(dst, src, size)
30340266059SGregory Neil Shapiro register char **dst;
30440266059SGregory Neil Shapiro register const char *src;
30540266059SGregory Neil Shapiro ssize_t size;
30640266059SGregory Neil Shapiro {
30740266059SGregory Neil Shapiro register size_t i;
30840266059SGregory Neil Shapiro
30940266059SGregory Neil Shapiro if (size-- <= 0)
31040266059SGregory Neil Shapiro return false;
31140266059SGregory Neil Shapiro for (i = 0; i < size && ((*dst)[i] = src[i]) != '\0'; i++)
31240266059SGregory Neil Shapiro continue;
31340266059SGregory Neil Shapiro (*dst)[i] = '\0';
31440266059SGregory Neil Shapiro if (src[i] == '\0')
31540266059SGregory Neil Shapiro {
31640266059SGregory Neil Shapiro *dst += i;
31740266059SGregory Neil Shapiro return true;
31840266059SGregory Neil Shapiro }
31940266059SGregory Neil Shapiro
32040266059SGregory Neil Shapiro /* undo */
32140266059SGregory Neil Shapiro (*dst)[0] = '\0';
32240266059SGregory Neil Shapiro return false;
32340266059SGregory Neil Shapiro }
32440266059SGregory Neil Shapiro #endif /* 0 */
325