190792Sgshapiro/* 2261194Sgshapiro * Copyright (c) 1999-2002 Proofpoint, Inc. and its suppliers. 390792Sgshapiro * All rights reserved. 490792Sgshapiro * 590792Sgshapiro * By using this file, you agree to the terms and conditions set 690792Sgshapiro * forth in the LICENSE file which can be found at the top level of 790792Sgshapiro * the sendmail distribution. 890792Sgshapiro * 990792Sgshapiro */ 1090792Sgshapiro 1190792Sgshapiro#include <sm/gen.h> 12266527SgshapiroSM_RCSID("@(#)$Id: strl.c,v 1.32 2013-11-22 20:51:43 ca Exp $") 1390792Sgshapiro#include <sm/config.h> 1490792Sgshapiro#include <sm/string.h> 1590792Sgshapiro 1690792Sgshapiro/* 1790792Sgshapiro** Notice: this file is used by libmilter. Please try to avoid 1890792Sgshapiro** using libsm specific functions. 1990792Sgshapiro*/ 2090792Sgshapiro 2190792Sgshapiro/* 2290792Sgshapiro** XXX the type of the length parameter has been changed 2390792Sgshapiro** from size_t to ssize_t to avoid theoretical problems with negative 2490792Sgshapiro** numbers passed into these functions. 2590792Sgshapiro** The real solution to this problem is to make sure that this doesn't 2690792Sgshapiro** happen, but for now we'll use this workaround. 2790792Sgshapiro*/ 2890792Sgshapiro 2990792Sgshapiro/* 3090792Sgshapiro** SM_STRLCPY -- size bounded string copy 3190792Sgshapiro** 3290792Sgshapiro** This is a bounds-checking variant of strcpy. 3390792Sgshapiro** If size > 0, copy up to size-1 characters from the nul terminated 3490792Sgshapiro** string src to dst, nul terminating the result. If size == 0, 3590792Sgshapiro** the dst buffer is not modified. 3690792Sgshapiro** Additional note: this function has been "tuned" to run fast and tested 3790792Sgshapiro** as such (versus versions in some OS's libc). 3890792Sgshapiro** 3990792Sgshapiro** The result is strlen(src). You can detect truncation (not all 4090792Sgshapiro** of the characters in the source string were copied) using the 4190792Sgshapiro** following idiom: 4290792Sgshapiro** 4390792Sgshapiro** char *s, buf[BUFSIZ]; 4490792Sgshapiro** ... 4590792Sgshapiro** if (sm_strlcpy(buf, s, sizeof(buf)) >= sizeof(buf)) 4690792Sgshapiro** goto overflow; 4790792Sgshapiro** 4890792Sgshapiro** Parameters: 4990792Sgshapiro** dst -- destination buffer 5090792Sgshapiro** src -- source string 5190792Sgshapiro** size -- size of destination buffer 5290792Sgshapiro** 5390792Sgshapiro** Returns: 5490792Sgshapiro** strlen(src) 5590792Sgshapiro*/ 5690792Sgshapiro 5790792Sgshapirosize_t 5890792Sgshapirosm_strlcpy(dst, src, size) 5990792Sgshapiro register char *dst; 6090792Sgshapiro register const char *src; 6190792Sgshapiro ssize_t size; 6290792Sgshapiro{ 6390792Sgshapiro register ssize_t i; 6490792Sgshapiro 6590792Sgshapiro if (size-- <= 0) 6690792Sgshapiro return strlen(src); 6790792Sgshapiro for (i = 0; i < size && (dst[i] = src[i]) != 0; i++) 6890792Sgshapiro continue; 6990792Sgshapiro dst[i] = '\0'; 7090792Sgshapiro if (src[i] == '\0') 7190792Sgshapiro return i; 7290792Sgshapiro else 7390792Sgshapiro return i + strlen(src + i); 7490792Sgshapiro} 7590792Sgshapiro 7690792Sgshapiro/* 7790792Sgshapiro** SM_STRLCAT -- size bounded string concatenation 7890792Sgshapiro** 7990792Sgshapiro** This is a bounds-checking variant of strcat. 8090792Sgshapiro** If strlen(dst) < size, then append at most size - strlen(dst) - 1 8190792Sgshapiro** characters from the source string to the destination string, 8290792Sgshapiro** nul terminating the result. Otherwise, dst is not modified. 8390792Sgshapiro** 8490792Sgshapiro** The result is the initial length of dst + the length of src. 8590792Sgshapiro** You can detect overflow (not all of the characters in the 8690792Sgshapiro** source string were copied) using the following idiom: 8790792Sgshapiro** 8890792Sgshapiro** char *s, buf[BUFSIZ]; 8990792Sgshapiro** ... 9090792Sgshapiro** if (sm_strlcat(buf, s, sizeof(buf)) >= sizeof(buf)) 9190792Sgshapiro** goto overflow; 9290792Sgshapiro** 9390792Sgshapiro** Parameters: 9490792Sgshapiro** dst -- nul-terminated destination string buffer 9590792Sgshapiro** src -- nul-terminated source string 9690792Sgshapiro** size -- size of destination buffer 9790792Sgshapiro** 9890792Sgshapiro** Returns: 9990792Sgshapiro** total length of the string tried to create 10090792Sgshapiro** (= initial length of dst + length of src) 10190792Sgshapiro*/ 10290792Sgshapiro 10390792Sgshapirosize_t 10490792Sgshapirosm_strlcat(dst, src, size) 10590792Sgshapiro register char *dst; 10690792Sgshapiro register const char *src; 10790792Sgshapiro ssize_t size; 10890792Sgshapiro{ 10990792Sgshapiro register ssize_t i, j, o; 11090792Sgshapiro 11190792Sgshapiro o = strlen(dst); 11290792Sgshapiro if (size < o + 1) 11390792Sgshapiro return o + strlen(src); 11490792Sgshapiro size -= o + 1; 11590792Sgshapiro for (i = 0, j = o; i < size && (dst[j] = src[i]) != 0; i++, j++) 11690792Sgshapiro continue; 11790792Sgshapiro dst[j] = '\0'; 11890792Sgshapiro if (src[i] == '\0') 11990792Sgshapiro return j; 12090792Sgshapiro else 12190792Sgshapiro return j + strlen(src + i); 12290792Sgshapiro} 12390792Sgshapiro/* 12490792Sgshapiro** SM_STRLCAT2 -- append two strings to dst obeying length and 12590792Sgshapiro** '\0' terminate it 12690792Sgshapiro** 12790792Sgshapiro** strlcat2 will append at most len - strlen(dst) - 1 chars. 12890792Sgshapiro** terminates with '\0' if len > 0 12990792Sgshapiro** dst = dst "+" src1 "+" src2 13090792Sgshapiro** use this instead of sm_strlcat(dst,src1); sm_strlcat(dst,src2); 13190792Sgshapiro** for better speed. 13290792Sgshapiro** 13390792Sgshapiro** Parameters: 13490792Sgshapiro** dst -- "destination" string. 13590792Sgshapiro** src1 -- "from" string 1. 13690792Sgshapiro** src2 -- "from" string 2. 13790792Sgshapiro** len -- max. length of "destination" string. 13890792Sgshapiro** 13990792Sgshapiro** Returns: 14090792Sgshapiro** total length of the string tried to create 14190792Sgshapiro** (= initial length of dst + length of src) 14290792Sgshapiro** if this is greater than len then an overflow would have 14390792Sgshapiro** occurred. 14490792Sgshapiro** 14590792Sgshapiro*/ 14690792Sgshapiro 14790792Sgshapirosize_t 14890792Sgshapirosm_strlcat2(dst, src1, src2, len) 14990792Sgshapiro register char *dst; 15090792Sgshapiro register const char *src1; 15190792Sgshapiro register const char *src2; 15290792Sgshapiro ssize_t len; 15390792Sgshapiro{ 15490792Sgshapiro register ssize_t i, j, o; 15590792Sgshapiro 15690792Sgshapiro /* current size of dst */ 15790792Sgshapiro o = strlen(dst); 15890792Sgshapiro 15990792Sgshapiro /* max. size is less than current? */ 16090792Sgshapiro if (len < o + 1) 16190792Sgshapiro return o + strlen(src1) + strlen(src2); 16290792Sgshapiro 16390792Sgshapiro len -= o + 1; /* space left in dst */ 16490792Sgshapiro 16590792Sgshapiro /* copy the first string; i: index in src1; j: index in dst */ 16690792Sgshapiro for (i = 0, j = o; i < len && (dst[j] = src1[i]) != 0; i++, j++) 16790792Sgshapiro continue; 16890792Sgshapiro 16990792Sgshapiro /* src1: end reached? */ 17090792Sgshapiro if (src1[i] != '\0') 17190792Sgshapiro { 17290792Sgshapiro /* no: terminate dst; there is space since i < len */ 17390792Sgshapiro dst[j] = '\0'; 17490792Sgshapiro return j + strlen(src1 + i) + strlen(src2); 17590792Sgshapiro } 17690792Sgshapiro 17790792Sgshapiro len -= i; /* space left in dst */ 17890792Sgshapiro 17990792Sgshapiro /* copy the second string; i: index in src2; j: index in dst */ 18090792Sgshapiro for (i = 0; i < len && (dst[j] = src2[i]) != 0; i++, j++) 18190792Sgshapiro continue; 18290792Sgshapiro dst[j] = '\0'; /* terminate dst; there is space since i < len */ 18390792Sgshapiro if (src2[i] == '\0') 18490792Sgshapiro return j; 18590792Sgshapiro else 18690792Sgshapiro return j + strlen(src2 + i); 18790792Sgshapiro} 18890792Sgshapiro 18990792Sgshapiro/* 19090792Sgshapiro** SM_STRLCPYN -- concatenate n strings and assign the result to dst 19190792Sgshapiro** while obeying length and '\0' terminate it 19290792Sgshapiro** 19390792Sgshapiro** dst = src1 "+" src2 "+" ... 19490792Sgshapiro** use this instead of sm_snprintf() for string values 19590792Sgshapiro** and repeated sm_strlc*() calls for better speed. 19690792Sgshapiro** 19790792Sgshapiro** Parameters: 19890792Sgshapiro** dst -- "destination" string. 19990792Sgshapiro** len -- max. length of "destination" string. 20090792Sgshapiro** n -- number of strings 20190792Sgshapiro** strings... 20290792Sgshapiro** 20390792Sgshapiro** Returns: 20490792Sgshapiro** total length of the string tried to create 20590792Sgshapiro** (= initial length of dst + length of src) 20690792Sgshapiro** if this is greater than len then an overflow would have 20790792Sgshapiro** occurred. 20890792Sgshapiro*/ 20990792Sgshapiro 21090792Sgshapirosize_t 21190792Sgshapiro#ifdef __STDC__ 21290792Sgshapirosm_strlcpyn(char *dst, ssize_t len, int n, ...) 21390792Sgshapiro#else /* __STDC__ */ 21490792Sgshapirosm_strlcpyn(dst, len, n, va_alist) 21590792Sgshapiro register char *dst; 21690792Sgshapiro ssize_t len; 21790792Sgshapiro int n; 21890792Sgshapiro va_dcl 21990792Sgshapiro#endif /* __STDC__ */ 22090792Sgshapiro{ 22190792Sgshapiro register ssize_t i, j; 22290792Sgshapiro char *str; 22390792Sgshapiro SM_VA_LOCAL_DECL 22490792Sgshapiro 22590792Sgshapiro SM_VA_START(ap, n); 22690792Sgshapiro 22790792Sgshapiro if (len-- <= 0) /* This allows space for the terminating '\0' */ 22890792Sgshapiro { 22990792Sgshapiro i = 0; 23090792Sgshapiro while (n-- > 0) 23190792Sgshapiro i += strlen(SM_VA_ARG(ap, char *)); 23294334Sgshapiro SM_VA_END(ap); 23390792Sgshapiro return i; 23490792Sgshapiro } 23590792Sgshapiro 23690792Sgshapiro j = 0; /* index in dst */ 23790792Sgshapiro 23890792Sgshapiro /* loop through all source strings */ 23990792Sgshapiro while (n-- > 0) 24090792Sgshapiro { 24190792Sgshapiro str = SM_VA_ARG(ap, char *); 24290792Sgshapiro 24390792Sgshapiro /* copy string; i: index in str; j: index in dst */ 24490792Sgshapiro for (i = 0; j < len && (dst[j] = str[i]) != 0; i++, j++) 24590792Sgshapiro continue; 24690792Sgshapiro 24790792Sgshapiro /* str: end reached? */ 24890792Sgshapiro if (str[i] != '\0') 24990792Sgshapiro { 25090792Sgshapiro /* no: terminate dst; there is space since j < len */ 25190792Sgshapiro dst[j] = '\0'; 25290792Sgshapiro j += strlen(str + i); 25390792Sgshapiro while (n-- > 0) 25490792Sgshapiro j += strlen(SM_VA_ARG(ap, char *)); 25594334Sgshapiro SM_VA_END(ap); 25690792Sgshapiro return j; 25790792Sgshapiro } 25890792Sgshapiro } 25994334Sgshapiro SM_VA_END(ap); 26090792Sgshapiro 26190792Sgshapiro dst[j] = '\0'; /* terminate dst; there is space since j < len */ 26290792Sgshapiro return j; 26390792Sgshapiro} 26490792Sgshapiro 26590792Sgshapiro#if 0 26690792Sgshapiro/* 26790792Sgshapiro** SM_STRLAPP -- append string if it fits into buffer. 26890792Sgshapiro** 26990792Sgshapiro** If size > 0, copy up to size-1 characters from the nul terminated 27090792Sgshapiro** string src to dst, nul terminating the result. If size == 0, 27190792Sgshapiro** the dst buffer is not modified. 27290792Sgshapiro** 27390792Sgshapiro** This routine is useful for appending strings in a loop, e.g, instead of 27490792Sgshapiro** s = buf; 27590792Sgshapiro** for (ptr, ptr != NULL, ptr = next->ptr) 27690792Sgshapiro** { 27790792Sgshapiro** (void) sm_strlcpy(s, ptr->string, sizeof buf - (s - buf)); 27890792Sgshapiro** s += strlen(s); 27990792Sgshapiro** } 28090792Sgshapiro** replace the loop body with: 28190792Sgshapiro** if (!sm_strlapp(*s, ptr->string, sizeof buf - (s - buf))) 28290792Sgshapiro** break; 28390792Sgshapiro** it's faster... 28490792Sgshapiro** 28590792Sgshapiro** XXX interface isn't completely clear (yet), hence this code is 28690792Sgshapiro** not available. 28790792Sgshapiro** 28890792Sgshapiro** 28990792Sgshapiro** Parameters: 29090792Sgshapiro** dst -- (pointer to) destination buffer 29190792Sgshapiro** src -- source string 29290792Sgshapiro** size -- size of destination buffer 29390792Sgshapiro** 29490792Sgshapiro** Returns: 29590792Sgshapiro** true if strlen(src) < size 29690792Sgshapiro** 29790792Sgshapiro** Side Effects: 29890792Sgshapiro** modifies dst if append succeeds (enough space). 29990792Sgshapiro*/ 30090792Sgshapiro 30190792Sgshapirobool 30290792Sgshapirosm_strlapp(dst, src, size) 30390792Sgshapiro register char **dst; 30490792Sgshapiro register const char *src; 30590792Sgshapiro ssize_t size; 30690792Sgshapiro{ 30790792Sgshapiro register size_t i; 30890792Sgshapiro 30990792Sgshapiro if (size-- <= 0) 31090792Sgshapiro return false; 31190792Sgshapiro for (i = 0; i < size && ((*dst)[i] = src[i]) != '\0'; i++) 31290792Sgshapiro continue; 31390792Sgshapiro (*dst)[i] = '\0'; 31490792Sgshapiro if (src[i] == '\0') 31590792Sgshapiro { 31690792Sgshapiro *dst += i; 31790792Sgshapiro return true; 31890792Sgshapiro } 31990792Sgshapiro 32090792Sgshapiro /* undo */ 32190792Sgshapiro (*dst)[0] = '\0'; 32290792Sgshapiro return false; 32390792Sgshapiro} 32490792Sgshapiro#endif /* 0 */ 325