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