1 /* 2 * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1997 Eric P. Allman. All rights reserved. 5 * Copyright (c) 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * By using this file, you agree to the terms and conditions set 9 * forth in the LICENSE file which can be found at the top level of 10 * the sendmail distribution. 11 * 12 */ 13 14 #ifndef lint 15 static char id[] = "@(#)$Id: snprintf.c,v 8.27.16.2 2000/09/17 17:04:24 gshapiro Exp $"; 16 #endif /* ! lint */ 17 18 #include <sendmail.h> 19 20 /* 21 ** SNPRINTF, VSNPRINT -- counted versions of printf 22 ** 23 ** These versions have been grabbed off the net. They have been 24 ** cleaned up to compile properly and support for .precision and 25 ** %lx has been added. 26 */ 27 28 /************************************************************** 29 * Original: 30 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 31 * A bombproof version of doprnt (sm_dopr) included. 32 * Sigh. This sort of thing is always nasty do deal with. Note that 33 * the version here does not include floating point... 34 * 35 * snprintf() is used instead of sprintf() as it does limit checks 36 * for string length. This covers a nasty loophole. 37 * 38 * The other functions are there to prevent NULL pointers from 39 * causing nast effects. 40 **************************************************************/ 41 42 /*static char _id[] = "$OrigId: snprintf.c,v 1.2 1995/10/09 11:19:47 roberto Exp $";*/ 43 void sm_dopr(); 44 char *DoprEnd; 45 int SnprfOverflow; 46 47 #if !HASSNPRINTF && !SNPRINTF_IS_BROKEN 48 # define sm_snprintf snprintf 49 # ifndef luna2 50 # define sm_vsnprintf vsnprintf 51 extern int vsnprintf __P((char *, size_t, const char *, va_list)); 52 # endif /* ! luna2 */ 53 #endif /* !HASSNPRINTF && !SNPRINTF_IS_BROKEN */ 54 55 /* VARARGS3 */ 56 int 57 # ifdef __STDC__ 58 sm_snprintf(char *str, size_t count, const char *fmt, ...) 59 # else /* __STDC__ */ 60 sm_snprintf(str, count, fmt, va_alist) 61 char *str; 62 size_t count; 63 const char *fmt; 64 va_dcl 65 # endif /* __STDC__ */ 66 { 67 int len; 68 VA_LOCAL_DECL 69 70 VA_START(fmt); 71 len = sm_vsnprintf(str, count, fmt, ap); 72 VA_END; 73 return len; 74 } 75 76 int 77 sm_vsnprintf(str, count, fmt, args) 78 char *str; 79 size_t count; 80 const char *fmt; 81 va_list args; 82 { 83 str[0] = 0; 84 DoprEnd = str + count - 1; 85 SnprfOverflow = 0; 86 sm_dopr( str, fmt, args ); 87 if (count > 0) 88 DoprEnd[0] = 0; 89 if (SnprfOverflow && tTd(57, 2)) 90 dprintf("\nvsnprintf overflow, len = %ld, str = %s", 91 (long) count, shortenstring(str, MAXSHORTSTR)); 92 return strlen(str); 93 } 94 95 /* 96 * sm_dopr(): poor man's version of doprintf 97 */ 98 99 void fmtstr __P((char *value, int ljust, int len, int zpad, int maxwidth)); 100 void fmtnum __P((long value, int base, int dosign, int ljust, int len, int zpad)); 101 void dostr __P(( char * , int )); 102 char *output; 103 void dopr_outch __P(( int c )); 104 int SyslogErrno; 105 106 void 107 sm_dopr( buffer, format, args ) 108 char *buffer; 109 const char *format; 110 va_list args; 111 { 112 int ch; 113 long value; 114 int longflag = 0; 115 int pointflag = 0; 116 int maxwidth = 0; 117 char *strvalue; 118 int ljust; 119 int len; 120 int zpad; 121 #if !HASSTRERROR && !defined(ERRLIST_PREDEFINED) 122 extern char *sys_errlist[]; 123 extern int sys_nerr; 124 #endif /* !HASSTRERROR && !defined(ERRLIST_PREDEFINED) */ 125 126 127 output = buffer; 128 while( (ch = *format++) != '\0' ){ 129 switch( ch ){ 130 case '%': 131 ljust = len = zpad = maxwidth = 0; 132 longflag = pointflag = 0; 133 nextch: 134 ch = *format++; 135 switch( ch ){ 136 case 0: 137 dostr( "**end of format**" , 0); 138 return; 139 case '-': ljust = 1; goto nextch; 140 case '0': /* set zero padding if len not set */ 141 if(len==0 && !pointflag) zpad = '0'; 142 /* FALLTHROUGH */ 143 case '1': case '2': case '3': 144 case '4': case '5': case '6': 145 case '7': case '8': case '9': 146 if (pointflag) 147 maxwidth = maxwidth*10 + ch - '0'; 148 else 149 len = len*10 + ch - '0'; 150 goto nextch; 151 case '*': 152 if (pointflag) 153 maxwidth = va_arg( args, int ); 154 else 155 len = va_arg( args, int ); 156 goto nextch; 157 case '.': pointflag = 1; goto nextch; 158 case 'l': longflag = 1; goto nextch; 159 case 'u': case 'U': 160 /*fmtnum(value,base,dosign,ljust,len,zpad) */ 161 if( longflag ){ 162 value = va_arg( args, long ); 163 } else { 164 value = va_arg( args, int ); 165 } 166 fmtnum( value, 10,0, ljust, len, zpad ); break; 167 case 'o': case 'O': 168 /*fmtnum(value,base,dosign,ljust,len,zpad) */ 169 if( longflag ){ 170 value = va_arg( args, long ); 171 } else { 172 value = va_arg( args, int ); 173 } 174 fmtnum( value, 8,0, ljust, len, zpad ); break; 175 case 'd': case 'D': 176 if( longflag ){ 177 value = va_arg( args, long ); 178 } else { 179 value = va_arg( args, int ); 180 } 181 fmtnum( value, 10,1, ljust, len, zpad ); break; 182 case 'x': 183 if( longflag ){ 184 value = va_arg( args, long ); 185 } else { 186 value = va_arg( args, int ); 187 } 188 fmtnum( value, 16,0, ljust, len, zpad ); break; 189 case 'X': 190 if( longflag ){ 191 value = va_arg( args, long ); 192 } else { 193 value = va_arg( args, int ); 194 } 195 fmtnum( value,-16,0, ljust, len, zpad ); break; 196 case 's': 197 strvalue = va_arg( args, char *); 198 if (maxwidth > 0 || !pointflag) { 199 if (pointflag && len > maxwidth) 200 len = maxwidth; /* Adjust padding */ 201 fmtstr( strvalue,ljust,len,zpad, maxwidth); 202 } 203 break; 204 case 'c': 205 ch = va_arg( args, int ); 206 dopr_outch( ch ); break; 207 case 'm': 208 #if HASSTRERROR 209 dostr(strerror(SyslogErrno), 0); 210 #else /* HASSTRERROR */ 211 if (SyslogErrno < 0 || SyslogErrno >= sys_nerr) 212 { 213 dostr("Error ", 0); 214 fmtnum(SyslogErrno, 10, 0, 0, 0, 0); 215 } 216 else 217 dostr((char *)sys_errlist[SyslogErrno], 0); 218 #endif /* HASSTRERROR */ 219 break; 220 221 case '%': dopr_outch( ch ); continue; 222 default: 223 dostr( "???????" , 0); 224 } 225 break; 226 default: 227 dopr_outch( ch ); 228 break; 229 } 230 } 231 *output = 0; 232 } 233 234 void 235 fmtstr( value, ljust, len, zpad, maxwidth ) 236 char *value; 237 int ljust, len, zpad, maxwidth; 238 { 239 int padlen, strleng; /* amount to pad */ 240 241 if( value == 0 ){ 242 value = "<NULL>"; 243 } 244 for( strleng = 0; value[strleng]; ++ strleng ); /* strlen */ 245 if (strleng > maxwidth && maxwidth) 246 strleng = maxwidth; 247 padlen = len - strleng; 248 if( padlen < 0 ) padlen = 0; 249 if( ljust ) padlen = -padlen; 250 while( padlen > 0 ) { 251 dopr_outch( ' ' ); 252 --padlen; 253 } 254 dostr( value, maxwidth ); 255 while( padlen < 0 ) { 256 dopr_outch( ' ' ); 257 ++padlen; 258 } 259 } 260 261 void 262 fmtnum( value, base, dosign, ljust, len, zpad ) 263 long value; 264 int base, dosign, ljust, len, zpad; 265 { 266 int signvalue = 0; 267 unsigned long uvalue; 268 char convert[20]; 269 int place = 0; 270 int padlen = 0; /* amount to pad */ 271 int caps = 0; 272 273 /* DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n", 274 value, base, dosign, ljust, len, zpad )); */ 275 uvalue = value; 276 if( dosign ){ 277 if( value < 0 ) { 278 signvalue = '-'; 279 uvalue = -value; 280 } 281 } 282 if( base < 0 ){ 283 caps = 1; 284 base = -base; 285 } 286 do{ 287 convert[place++] = 288 (caps? "0123456789ABCDEF":"0123456789abcdef") 289 [uvalue % (unsigned)base ]; 290 uvalue = (uvalue / (unsigned)base ); 291 }while(uvalue); 292 convert[place] = 0; 293 padlen = len - place; 294 if( padlen < 0 ) padlen = 0; 295 if( ljust ) padlen = -padlen; 296 /* DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n", 297 convert,place,signvalue,padlen)); */ 298 if( zpad && padlen > 0 ){ 299 if( signvalue ){ 300 dopr_outch( signvalue ); 301 --padlen; 302 signvalue = 0; 303 } 304 while( padlen > 0 ){ 305 dopr_outch( zpad ); 306 --padlen; 307 } 308 } 309 while( padlen > 0 ) { 310 dopr_outch( ' ' ); 311 --padlen; 312 } 313 if( signvalue ) dopr_outch( signvalue ); 314 while( place > 0 ) dopr_outch( convert[--place] ); 315 while( padlen < 0 ){ 316 dopr_outch( ' ' ); 317 ++padlen; 318 } 319 } 320 321 void 322 dostr( str , cut) 323 char *str; 324 int cut; 325 { 326 if (cut) { 327 while(*str && cut-- > 0) dopr_outch(*str++); 328 } else { 329 while(*str) dopr_outch(*str++); 330 } 331 } 332 333 void 334 dopr_outch( c ) 335 int c; 336 { 337 #if 0 338 if( iscntrl(c) && c != '\n' && c != '\t' ){ 339 c = '@' + (c & 0x1F); 340 if( DoprEnd == 0 || output < DoprEnd ) 341 *output++ = '^'; 342 } 343 #endif /* 0 */ 344 if( DoprEnd == 0 || output < DoprEnd ) 345 *output++ = c; 346 else 347 SnprfOverflow++; 348 } 349 350 /* 351 ** QUAD_TO_STRING -- Convert a quad type to a string. 352 ** 353 ** Convert a quad type to a string. This must be done 354 ** separately as %lld/%qd are not supported by snprint() 355 ** and adding support would slow down systems which only 356 ** emulate the data type. 357 ** 358 ** Parameters: 359 ** value -- number to convert to a string. 360 ** 361 ** Returns: 362 ** pointer to a string. 363 */ 364 365 char * 366 quad_to_string(value) 367 QUAD_T value; 368 { 369 char *formatstr; 370 static char buf[64]; 371 372 /* 373 ** Use sprintf() instead of snprintf() since snprintf() 374 ** does not support %qu or %llu. The buffer is large enough 375 ** to hold the string so there is no danger of buffer 376 ** overflow. 377 */ 378 379 #if NEED_PERCENTQ 380 formatstr = "%qu"; 381 #else /* NEED_PERCENTQ */ 382 formatstr = "%llu"; 383 #endif /* NEED_PERCENTQ */ 384 sprintf(buf, formatstr, value); 385 return buf; 386 } 387 /* 388 ** SHORTENSTRING -- return short version of a string 389 ** 390 ** If the string is already short, just return it. If it is too 391 ** long, return the head and tail of the string. 392 ** 393 ** Parameters: 394 ** s -- the string to shorten. 395 ** m -- the max length of the string (strlen()). 396 ** 397 ** Returns: 398 ** Either s or a short version of s. 399 */ 400 401 char * 402 shortenstring(s, m) 403 register const char *s; 404 int m; 405 { 406 int l; 407 static char buf[MAXSHORTSTR + 1]; 408 409 l = strlen(s); 410 if (l < m) 411 return (char *) s; 412 if (m > MAXSHORTSTR) 413 m = MAXSHORTSTR; 414 else if (m < 10) 415 { 416 if (m < 5) 417 { 418 (void) strlcpy(buf, s, m + 1); 419 return buf; 420 } 421 (void) strlcpy(buf, s, m - 2); 422 (void) strlcat(buf, "...", sizeof buf); 423 return buf; 424 } 425 m = (m - 3) / 2; 426 (void) strlcpy(buf, s, m + 1); 427 (void) strlcat(buf, "...", sizeof buf); 428 (void) strlcat(buf, s + l - m, sizeof buf); 429 return buf; 430 } 431