1 /* $Id$ */
2 /*
3 ** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License Version 2 as
7 ** published by the Free Software Foundation. You may not use, modify or
8 ** distribute this program under any other version of the GNU General
9 ** Public License.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 /*
22 ** This file contains various routines which we shamelessly steal from other
23 ** opensource products :-P (I love code reuseability idea)
24 ** fygrave@tigerteam.net
25 */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #ifndef HAVE_SNPRINTF
32 #include "snprintf.h"
33
34 /* snprintf() and all supporting routines were taken from sendmail, hence the
35 * copyleft message
36 */
37
38 /*
39 * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
40 * Copyright (c) 1997 Eric P. Allman. All rights reserved.
41 * Copyright (c) 1988, 1993
42 * The Regents of the University of California. All rights reserved.
43 *
44 * By using this file, you agree to the terms and conditions set
45 * forth in the LICENSE file which can be found at the top level of
46 * the sendmail distribution.
47 *
48 */
49
50 /*
51 ** SNPRINTF, VSNPRINT -- counted versions of printf
52 **
53 ** These versions have been grabbed off the net. They have been
54 ** cleaned up to compile properly and support for .precision and
55 ** %lx has been added.
56 */
57
58 /**************************************************************
59 * Original:
60 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
61 * A bombproof version of doprnt (sm_dopr) included.
62 * Sigh. This sort of thing is always nasty do deal with. Note that
63 * the version here does not include floating point...
64 *
65 * snprintf() is used instead of sprintf() as it does limit checks
66 * for string length. This covers a nasty loophole.
67 *
68 * The other functions are there to prevent NULL pointers from
69 * causing nast effects.
70 **************************************************************/
71
72 void sm_dopr();
73 char *DoprEnd;
74 int SnprfOverflow;
75
76 #ifndef HAVE_SNPRINTF
77
78 /* VARARGS3 */
79 int
80 #ifdef __STDC__
snprintf(char * str,size_t count,const char * fmt,...)81 snprintf(char *str, size_t count, const char *fmt, ...)
82 #else
83 snprintf(str, count, fmt, va_alist)
84 char *str;
85 size_t count;
86 const char *fmt;
87 va_dcl
88 #endif
89 {
90 int len;
91 VA_LOCAL_DECL
92
93 VA_START(fmt);
94 len = vsnprintf(str, count, fmt, ap);
95 VA_END;
96 return len;
97 }
98
99
100 #ifndef luna2
101 #ifndef HAVE_VSNPRINTF
102
103 int
vsnprintf(str,count,fmt,args)104 vsnprintf(str, count, fmt, args)
105 char *str;
106 size_t count;
107 const char *fmt;
108 va_list args;
109 {
110 str[0] = 0;
111 DoprEnd = str + count - 1;
112 SnprfOverflow = 0;
113 sm_dopr( str, fmt, args );
114 if(count > 0)
115 DoprEnd[0] = 0;
116 if(SnprfOverflow && tTd(57, 2))
117 printf("\nvsnprintf overflow, len = %ld, str = %s",
118 (long) count, shortenstring(str, MAXSHORTSTR));
119 return strlen((const char *)str);
120 }
121
122 #endif /* !HAVE_VSNPRINTF */
123
124 #endif /* !luna2 */
125 #endif /* !HASSNPRINTF */
126
127 /*
128 * sm_dopr(): poor man's version of doprintf
129 */
130
131 void fmtstr __P((char *value, int ljust, int len, int zpad, int maxwidth));
132 void fmtnum __P((long value, int base, int dosign, int ljust, int len, int zpad));
133 void dostr __P(( char * , int ));
134 char *output;
135 void dopr_outch __P(( int c ));
136 int SyslogErrno;
137
138 void
sm_dopr(buffer,format,args)139 sm_dopr( buffer, format, args )
140 char *buffer;
141 const char *format;
142 va_list args;
143 {
144 int ch;
145 long value;
146 int longflag = 0;
147 int pointflag = 0;
148 int maxwidth = 0;
149 char *strvalue;
150 int ljust;
151 int len;
152 int zpad;
153 #if !HAVE_STRERROR && !defined(ERRLIST_PREDEFINED)
154 extern char *sys_errlist[];
155 extern int sys_nerr;
156 #endif
157
158
159 output = buffer;
160 while((ch = *format++) != '\0')
161 {
162 switch(ch)
163 {
164 case '%':
165 ljust = len = zpad = maxwidth = 0;
166 longflag = pointflag = 0;
167 nextch:
168 ch = *format++;
169 switch(ch)
170 {
171 case 0:
172 dostr( "**end of format**" , 0);
173 return;
174 case '-': ljust = 1; goto nextch;
175 case '0': /* set zero padding if len not set */
176 if(len==0 && !pointflag) zpad = '0';
177 case '1':
178 case '2':
179 case '3':
180 case '4':
181 case '5':
182 case '6':
183 case '7':
184 case '8':
185 case '9':
186 if(pointflag)
187 maxwidth = maxwidth*10 + ch - '0';
188 else
189 len = len*10 + ch - '0';
190 goto nextch;
191 case '*':
192 if(pointflag)
193 maxwidth = va_arg( args, int );
194 else
195 len = va_arg( args, int );
196 goto nextch;
197 case '.': pointflag = 1; goto nextch;
198 case 'l': longflag = 1; goto nextch;
199 case 'u':
200 case 'U':
201 /*fmtnum(value,base,dosign,ljust,len,zpad) */
202 if(longflag)
203 {
204 value = va_arg( args, long );
205 }
206 else
207 {
208 value = va_arg( args, int );
209 }
210 fmtnum( value, 10,0, ljust, len, zpad ); break;
211 case 'o':
212 case 'O':
213 /*fmtnum(value,base,dosign,ljust,len,zpad) */
214 if(longflag)
215 {
216 value = va_arg( args, long );
217 }
218 else
219 {
220 value = va_arg( args, int );
221 }
222 fmtnum( value, 8,0, ljust, len, zpad ); break;
223 case 'd':
224 case 'D':
225 if(longflag)
226 {
227 value = va_arg( args, long );
228 }
229 else
230 {
231 value = va_arg( args, int );
232 }
233 fmtnum( value, 10,1, ljust, len, zpad ); break;
234 case 'x':
235 if(longflag)
236 {
237 value = va_arg( args, long );
238 }
239 else
240 {
241 value = va_arg( args, int );
242 }
243 fmtnum( value, 16,0, ljust, len, zpad ); break;
244 case 'X':
245 if(longflag)
246 {
247 value = va_arg( args, long );
248 }
249 else
250 {
251 value = va_arg( args, int );
252 }
253 fmtnum( value,-16,0, ljust, len, zpad ); break;
254 case 's':
255 strvalue = va_arg( args, char *);
256 if(maxwidth > 0 || !pointflag)
257 {
258 if(pointflag && len > maxwidth)
259 len = maxwidth; /* Adjust padding */
260 fmtstr( strvalue,ljust,len,zpad, maxwidth);
261 }
262 break;
263 case 'c':
264 ch = va_arg( args, int );
265 dopr_outch( ch ); break;
266 case 'm':
267 #if HAVE_STRERROR
268 dostr(strerror(SyslogErrno), 0);
269 #else
270 if(SyslogErrno < 0 || SyslogErrno >= sys_nerr)
271 {
272 dostr("Error ", 0);
273 fmtnum(SyslogErrno, 10, 0, 0, 0, 0);
274 }
275 else
276 dostr((char *)sys_errlist[SyslogErrno], 0);
277 #endif
278 break;
279
280 case '%': dopr_outch( ch ); continue;
281 default:
282 dostr( "???????" , 0);
283 }
284 break;
285 default:
286 dopr_outch( ch );
287 break;
288 }
289 }
290 *output = 0;
291 }
292
293 void
fmtstr(value,ljust,len,zpad,maxwidth)294 fmtstr( value, ljust, len, zpad, maxwidth )
295 char *value;
296 int ljust, len, zpad, maxwidth;
297 {
298 int padlen, strlen; /* amount to pad */
299
300 if(value == 0)
301 {
302 value = "<NULL>";
303 }
304 for(strlen = 0; value[strlen]; ++ strlen); /* strlen */
305 if(strlen > maxwidth && maxwidth)
306 strlen = maxwidth;
307 padlen = len - strlen;
308 if(padlen < 0) padlen = 0;
309 if(ljust) padlen = -padlen;
310 while(padlen > 0)
311 {
312 dopr_outch( ' ' );
313 --padlen;
314 }
315 dostr( value, maxwidth );
316 while(padlen < 0)
317 {
318 dopr_outch( ' ' );
319 ++padlen;
320 }
321 }
322
323 void
fmtnum(value,base,dosign,ljust,len,zpad)324 fmtnum( value, base, dosign, ljust, len, zpad )
325 long value;
326 int base, dosign, ljust, len, zpad;
327 {
328 int signvalue = 0;
329 unsigned long uvalue;
330 char convert[20];
331 int place = 0;
332 int padlen = 0; /* amount to pad */
333 int caps = 0;
334
335 /* DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n",
336 value, base, dosign, ljust, len, zpad )); */
337 uvalue = value;
338 if(dosign)
339 {
340 if(value < 0)
341 {
342 signvalue = '-';
343 uvalue = -value;
344 }
345 }
346 if(base < 0)
347 {
348 caps = 1;
349 base = -base;
350 }
351 do
352 {
353 convert[place++] =
354 (caps? "0123456789ABCDEF":"0123456789abcdef")
355 [uvalue % (unsigned)base ];
356 uvalue = (uvalue / (unsigned)base );
357 }while(uvalue);
358 convert[place] = 0;
359 padlen = len - place;
360 if(padlen < 0) padlen = 0;
361 if(ljust) padlen = -padlen;
362 /* DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n",
363 convert,place,signvalue,padlen)); */
364 if(zpad && padlen > 0)
365 {
366 if(signvalue)
367 {
368 dopr_outch( signvalue );
369 --padlen;
370 signvalue = 0;
371 }
372 while(padlen > 0)
373 {
374 dopr_outch( zpad );
375 --padlen;
376 }
377 }
378 while(padlen > 0)
379 {
380 dopr_outch( ' ' );
381 --padlen;
382 }
383 if(signvalue) dopr_outch( signvalue );
384 while(place > 0) dopr_outch( convert[--place] );
385 while(padlen < 0)
386 {
387 dopr_outch( ' ' );
388 ++padlen;
389 }
390 }
391
392 void
dostr(str,cut)393 dostr( str , cut)
394 char *str;
395 int cut;
396 {
397 if(cut)
398 {
399 while(*str && cut-- > 0) dopr_outch(*str++);
400 }
401 else
402 {
403 while(*str) dopr_outch(*str++);
404 }
405 }
406
407 void
dopr_outch(c)408 dopr_outch( c )
409 int c;
410 {
411 #if 0
412 if(iscntrl(c) && c != '\n' && c != '\t')
413 {
414 c = '@' + (c & 0x1F);
415 if(DoprEnd == 0 || output < DoprEnd)
416 *output++ = '^';
417 }
418 #endif
419 if(DoprEnd == 0 || output < DoprEnd)
420 *output++ = c;
421 else
422 SnprfOverflow++;
423 }
424
425 /*
426 ** QUAD_TO_STRING -- Convert a quad type to a string.
427 **
428 ** Convert a quad type to a string. This must be done
429 ** separately as %lld/%qd are not supported by snprint()
430 ** and adding support would slow down systems which only
431 ** emulate the data type.
432 **
433 ** Parameters:
434 ** value -- number to convert to a string.
435 **
436 ** Returns:
437 ** pointer to a string.
438 */
439
440 char *
quad_to_string(value)441 quad_to_string(value)
442 QUAD_T value;
443 {
444 char *fmtstr;
445 static char buf[64];
446
447 /*
448 ** Use sprintf() instead of snprintf() since snprintf()
449 ** does not support %qu or %llu. The buffer is large enough
450 ** to hold the string so there is no danger of buffer
451 ** overflow.
452 */
453
454 #if NEED_PERCENTQ
455 fmtstr = "%qu";
456 #elif SIZEOF_UNSIGNED_LONG_INT == 8
457 fmtstr = "%lu";
458 #else
459 fmtstr = "%llu";
460 #endif
461 sprintf(buf, fmtstr, value);
462 return buf;
463 }
464 /*
465 ** SHORTENSTRING -- return short version of a string
466 **
467 ** If the string is already short, just return it. If it is too
468 ** long, return the head and tail of the string.
469 **
470 ** Parameters:
471 ** s -- the string to shorten.
472 ** m -- the max length of the string.
473 **
474 ** Returns:
475 ** Either s or a short version of s.
476 */
477
478 char *
shortenstring(s,m)479 shortenstring(s, m)
480 register const char *s;
481 int m;
482 {
483 int l;
484 static char buf[MAXSHORTSTR + 1];
485
486 l = strlen(s);
487 if(l < m)
488 return(char *) s;
489 if(m > MAXSHORTSTR)
490 m = MAXSHORTSTR;
491 else if(m < 10)
492 {
493 if(m < 5)
494 {
495 strncpy(buf, s, m);
496 buf[m] = '\0';
497 return buf;
498 }
499 strncpy(buf, s, m - 3);
500 strcpy(buf + m - 3, "...");
501 return buf;
502 }
503 m = (m - 3) / 2;
504 strncpy(buf, s, m);
505 strcpy(buf + m, "...");
506 strcpy(buf + m + 3, s + l - m);
507 return buf;
508 }
509
510 #endif
511