File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / lib / snprintf.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Fri Feb 17 15:09:30 2012 UTC (12 years, 4 months ago) by misho
Branches: rsync, MAIN
CVS tags: rsync3_0_9p0, RSYNC3_0_9, HEAD
rsync

    1: /*
    2:  * NOTE: If you change this file, please merge it into rsync, samba, etc.
    3:  */
    4: 
    5: /*
    6:  * Copyright Patrick Powell 1995
    7:  * This code is based on code written by Patrick Powell (papowell@astart.com)
    8:  * It may be used for any purpose as long as this notice remains intact
    9:  * on all source code distributions
   10:  */
   11: 
   12: /**************************************************************
   13:  * Original:
   14:  * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
   15:  * A bombproof version of doprnt (dopr) included.
   16:  * Sigh.  This sort of thing is always nasty do deal with.  Note that
   17:  * the version here does not include floating point...
   18:  *
   19:  * snprintf() is used instead of sprintf() as it does limit checks
   20:  * for string length.  This covers a nasty loophole.
   21:  *
   22:  * The other functions are there to prevent NULL pointers from
   23:  * causing nast effects.
   24:  *
   25:  * More Recently:
   26:  *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
   27:  *  This was ugly.  It is still ugly.  I opted out of floating point
   28:  *  numbers, but the formatter understands just about everything
   29:  *  from the normal C string format, at least as far as I can tell from
   30:  *  the Solaris 2.5 printf(3S) man page.
   31:  *
   32:  *  Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
   33:  *    Ok, added some minimal floating point support, which means this
   34:  *    probably requires libm on most operating systems.  Don't yet
   35:  *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
   36:  *    was pretty badly broken, it just wasn't being exercised in ways
   37:  *    which showed it, so that's been fixed.  Also, formated the code
   38:  *    to mutt conventions, and removed dead code left over from the
   39:  *    original.  Also, there is now a builtin-test, just compile with:
   40:  *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
   41:  *    and run snprintf for results.
   42:  * 
   43:  *  Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
   44:  *    The PGP code was using unsigned hexadecimal formats. 
   45:  *    Unfortunately, unsigned formats simply didn't work.
   46:  *
   47:  *  Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
   48:  *    The original code assumed that both snprintf() and vsnprintf() were
   49:  *    missing.  Some systems only have snprintf() but not vsnprintf(), so
   50:  *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
   51:  *
   52:  *  Andrew Tridgell (tridge@samba.org) Oct 1998
   53:  *    fixed handling of %.0f
   54:  *    added test for HAVE_LONG_DOUBLE
   55:  *
   56:  * tridge@samba.org, idra@samba.org, April 2001
   57:  *    got rid of fcvt code (twas buggy and made testing harder)
   58:  *    added C99 semantics
   59:  *
   60:  * date: 2002/12/19 19:56:31;  author: herb;  state: Exp;  lines: +2 -0
   61:  * actually print args for %g and %e
   62:  * 
   63:  * date: 2002/06/03 13:37:52;  author: jmcd;  state: Exp;  lines: +8 -0
   64:  * Since includes.h isn't included here, VA_COPY has to be defined here.  I don't
   65:  * see any include file that is guaranteed to be here, so I'm defining it
   66:  * locally.  Fixes AIX and Solaris builds.
   67:  * 
   68:  * date: 2002/06/03 03:07:24;  author: tridge;  state: Exp;  lines: +5 -13
   69:  * put the ifdef for HAVE_VA_COPY in one place rather than in lots of
   70:  * functions
   71:  * 
   72:  * date: 2002/05/17 14:51:22;  author: jmcd;  state: Exp;  lines: +21 -4
   73:  * Fix usage of va_list passed as an arg.  Use __va_copy before using it
   74:  * when it exists.
   75:  * 
   76:  * date: 2002/04/16 22:38:04;  author: idra;  state: Exp;  lines: +20 -14
   77:  * Fix incorrect zpadlen handling in fmtfp.
   78:  * Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it.
   79:  * few mods to make it easier to compile the tests.
   80:  * addedd the "Ollie" test to the floating point ones.
   81:  *
   82:  * Martin Pool (mbp@samba.org) April 2003
   83:  *    Remove NO_CONFIG_H so that the test case can be built within a source
   84:  *    tree with less trouble.
   85:  *    Remove unnecessary SAFE_FREE() definition.
   86:  *
   87:  * Martin Pool (mbp@samba.org) May 2003
   88:  *    Put in a prototype for dummy_snprintf() to quiet compiler warnings.
   89:  *
   90:  *    Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
   91:  *    if the C library has some snprintf functions already.
   92:  **************************************************************/
   93: 
   94: #ifndef NO_CONFIG_H
   95: #include "config.h"
   96: #else
   97: #define NULL 0
   98: #endif 
   99: 
  100: #ifdef TEST_SNPRINTF /* need math library headers for testing */
  101: 
  102: /* In test mode, we pretend that this system doesn't have any snprintf
  103:  * functions, regardless of what config.h says. */
  104: #  undef HAVE_SNPRINTF
  105: #  undef HAVE_VSNPRINTF
  106: #  undef HAVE_C99_VSNPRINTF
  107: #  undef HAVE_ASPRINTF
  108: #  undef HAVE_VASPRINTF
  109: #  include <math.h>
  110: #endif /* TEST_SNPRINTF */
  111: 
  112: #ifdef HAVE_STRING_H
  113: #include <string.h>
  114: #endif
  115: 
  116: #ifdef HAVE_STRINGS_H
  117: #include <strings.h>
  118: #endif
  119: #ifdef HAVE_CTYPE_H
  120: #include <ctype.h>
  121: #endif
  122: #include <sys/types.h>
  123: #include <stdarg.h>
  124: #ifdef HAVE_STDLIB_H
  125: #include <stdlib.h>
  126: #endif
  127: 
  128: #if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)
  129: /* only include stdio.h if we are not re-defining snprintf or vsnprintf */
  130: #include <stdio.h>
  131:  /* make the compiler happy with an empty file */
  132:  void dummy_snprintf(void);
  133:  void dummy_snprintf(void) {} 
  134: #endif /* HAVE_SNPRINTF, etc */
  135: 
  136: #ifdef HAVE_LONG_DOUBLE
  137: #define LDOUBLE long double
  138: #else
  139: #define LDOUBLE double
  140: #endif
  141: 
  142: #if SIZEOF_LONG_LONG
  143: #define LLONG long long
  144: #else
  145: #define LLONG long
  146: #endif
  147: 
  148: #ifndef VA_COPY
  149: #if defined HAVE_VA_COPY || defined va_copy
  150: #define VA_COPY(dest, src) va_copy(dest, src)
  151: #else
  152: #ifdef HAVE___VA_COPY
  153: #define VA_COPY(dest, src) __va_copy(dest, src)
  154: #else
  155: #define VA_COPY(dest, src) (dest) = (src)
  156: #endif
  157: #endif
  158: 
  159: /*
  160:  * dopr(): poor man's version of doprintf
  161:  */
  162: 
  163: /* format read states */
  164: #define DP_S_DEFAULT 0
  165: #define DP_S_FLAGS   1
  166: #define DP_S_MIN     2
  167: #define DP_S_DOT     3
  168: #define DP_S_MAX     4
  169: #define DP_S_MOD     5
  170: #define DP_S_CONV    6
  171: #define DP_S_DONE    7
  172: 
  173: /* format flags - Bits */
  174: #define DP_F_MINUS 	(1 << 0)
  175: #define DP_F_PLUS  	(1 << 1)
  176: #define DP_F_SPACE 	(1 << 2)
  177: #define DP_F_NUM   	(1 << 3)
  178: #define DP_F_ZERO  	(1 << 4)
  179: #define DP_F_UP    	(1 << 5)
  180: #define DP_F_UNSIGNED 	(1 << 6)
  181: 
  182: /* Conversion Flags */
  183: #define DP_C_SHORT   1
  184: #define DP_C_LONG    2
  185: #define DP_C_LDOUBLE 3
  186: #define DP_C_LLONG   4
  187: 
  188: #define char_to_int(p) ((p)- '0')
  189: #ifndef MAX
  190: #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
  191: #endif
  192: 
  193: /* yes this really must be a ||. Don't muck with this (tridge) */
  194: #if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
  195: 
  196: static size_t dopr(char *buffer, size_t maxlen, const char *format, 
  197: 		   va_list args_in);
  198: static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
  199: 		    char *value, int flags, int min, int max);
  200: static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
  201: 		    long value, int base, int min, int max, int flags);
  202: static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
  203: 		   LDOUBLE fvalue, int min, int max, int flags);
  204: static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
  205: 
  206: static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
  207: {
  208: 	char ch;
  209: 	LLONG value;
  210: 	LDOUBLE fvalue;
  211: 	char *strvalue;
  212: 	int min;
  213: 	int max;
  214: 	int state;
  215: 	int flags;
  216: 	int cflags;
  217: 	size_t currlen;
  218: 	va_list args;
  219: 
  220: 	VA_COPY(args, args_in);
  221: 	
  222: 	state = DP_S_DEFAULT;
  223: 	currlen = flags = cflags = min = 0;
  224: 	max = -1;
  225: 	ch = *format++;
  226: 	
  227: 	while (state != DP_S_DONE) {
  228: 		if (ch == '\0') 
  229: 			state = DP_S_DONE;
  230: 
  231: 		switch(state) {
  232: 		case DP_S_DEFAULT:
  233: 			if (ch == '%') 
  234: 				state = DP_S_FLAGS;
  235: 			else 
  236: 				dopr_outch (buffer, &currlen, maxlen, ch);
  237: 			ch = *format++;
  238: 			break;
  239: 		case DP_S_FLAGS:
  240: 			switch (ch) {
  241: 			case '-':
  242: 				flags |= DP_F_MINUS;
  243: 				ch = *format++;
  244: 				break;
  245: 			case '+':
  246: 				flags |= DP_F_PLUS;
  247: 				ch = *format++;
  248: 				break;
  249: 			case ' ':
  250: 				flags |= DP_F_SPACE;
  251: 				ch = *format++;
  252: 				break;
  253: 			case '#':
  254: 				flags |= DP_F_NUM;
  255: 				ch = *format++;
  256: 				break;
  257: 			case '0':
  258: 				flags |= DP_F_ZERO;
  259: 				ch = *format++;
  260: 				break;
  261: 			default:
  262: 				state = DP_S_MIN;
  263: 				break;
  264: 			}
  265: 			break;
  266: 		case DP_S_MIN:
  267: 			if (isdigit((unsigned char)ch)) {
  268: 				min = 10*min + char_to_int (ch);
  269: 				ch = *format++;
  270: 			} else if (ch == '*') {
  271: 				min = va_arg (args, int);
  272: 				ch = *format++;
  273: 				state = DP_S_DOT;
  274: 			} else {
  275: 				state = DP_S_DOT;
  276: 			}
  277: 			break;
  278: 		case DP_S_DOT:
  279: 			if (ch == '.') {
  280: 				state = DP_S_MAX;
  281: 				ch = *format++;
  282: 			} else { 
  283: 				state = DP_S_MOD;
  284: 			}
  285: 			break;
  286: 		case DP_S_MAX:
  287: 			if (isdigit((unsigned char)ch)) {
  288: 				if (max < 0)
  289: 					max = 0;
  290: 				max = 10*max + char_to_int (ch);
  291: 				ch = *format++;
  292: 			} else if (ch == '*') {
  293: 				max = va_arg (args, int);
  294: 				ch = *format++;
  295: 				state = DP_S_MOD;
  296: 			} else {
  297: 				state = DP_S_MOD;
  298: 			}
  299: 			break;
  300: 		case DP_S_MOD:
  301: 			switch (ch) {
  302: 			case 'h':
  303: 				cflags = DP_C_SHORT;
  304: 				ch = *format++;
  305: 				break;
  306: 			case 'l':
  307: 				cflags = DP_C_LONG;
  308: 				ch = *format++;
  309: 				if (ch == 'l') {	/* It's a long long */
  310: 					cflags = DP_C_LLONG;
  311: 					ch = *format++;
  312: 				}
  313: 				break;
  314: 			case 'L':
  315: 				cflags = DP_C_LDOUBLE;
  316: 				ch = *format++;
  317: 				break;
  318: 			default:
  319: 				break;
  320: 			}
  321: 			state = DP_S_CONV;
  322: 			break;
  323: 		case DP_S_CONV:
  324: 			switch (ch) {
  325: 			case 'd':
  326: 			case 'i':
  327: 				if (cflags == DP_C_SHORT) 
  328: 					value = va_arg (args, int);
  329: 				else if (cflags == DP_C_LONG)
  330: 					value = va_arg (args, long int);
  331: 				else if (cflags == DP_C_LLONG)
  332: 					value = va_arg (args, LLONG);
  333: 				else
  334: 					value = va_arg (args, int);
  335: 				fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
  336: 				break;
  337: 			case 'o':
  338: 				flags |= DP_F_UNSIGNED;
  339: 				if (cflags == DP_C_SHORT)
  340: 					value = va_arg (args, unsigned int);
  341: 				else if (cflags == DP_C_LONG)
  342: 					value = (long)va_arg (args, unsigned long int);
  343: 				else if (cflags == DP_C_LLONG)
  344: 					value = (long)va_arg (args, unsigned LLONG);
  345: 				else
  346: 					value = (long)va_arg (args, unsigned int);
  347: 				fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
  348: 				break;
  349: 			case 'u':
  350: 				flags |= DP_F_UNSIGNED;
  351: 				if (cflags == DP_C_SHORT)
  352: 					value = va_arg (args, unsigned int);
  353: 				else if (cflags == DP_C_LONG)
  354: 					value = (long)va_arg (args, unsigned long int);
  355: 				else if (cflags == DP_C_LLONG)
  356: 					value = (LLONG)va_arg (args, unsigned LLONG);
  357: 				else
  358: 					value = (long)va_arg (args, unsigned int);
  359: 				fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
  360: 				break;
  361: 			case 'X':
  362: 				flags |= DP_F_UP;
  363: 			case 'x':
  364: 				flags |= DP_F_UNSIGNED;
  365: 				if (cflags == DP_C_SHORT)
  366: 					value = va_arg (args, unsigned int);
  367: 				else if (cflags == DP_C_LONG)
  368: 					value = (long)va_arg (args, unsigned long int);
  369: 				else if (cflags == DP_C_LLONG)
  370: 					value = (LLONG)va_arg (args, unsigned LLONG);
  371: 				else
  372: 					value = (long)va_arg (args, unsigned int);
  373: 				fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
  374: 				break;
  375: 			case 'f':
  376: 				if (cflags == DP_C_LDOUBLE)
  377: 					fvalue = va_arg (args, LDOUBLE);
  378: 				else
  379: 					fvalue = va_arg (args, double);
  380: 				/* um, floating point? */
  381: 				fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
  382: 				break;
  383: 			case 'E':
  384: 				flags |= DP_F_UP;
  385: 			case 'e':
  386: 				if (cflags == DP_C_LDOUBLE)
  387: 					fvalue = va_arg (args, LDOUBLE);
  388: 				else
  389: 					fvalue = va_arg (args, double);
  390: 				fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
  391: 				break;
  392: 			case 'G':
  393: 				flags |= DP_F_UP;
  394: 			case 'g':
  395: 				if (cflags == DP_C_LDOUBLE)
  396: 					fvalue = va_arg (args, LDOUBLE);
  397: 				else
  398: 					fvalue = va_arg (args, double);
  399: 				fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
  400: 				break;
  401: 			case 'c':
  402: 				dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
  403: 				break;
  404: 			case 's':
  405: 				strvalue = va_arg (args, char *);
  406: 				if (!strvalue) strvalue = "(NULL)";
  407: 				if (max == -1) {
  408: 					max = strlen(strvalue);
  409: 				}
  410: 				if (min > 0 && max >= 0 && min > max) max = min;
  411: 				fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
  412: 				break;
  413: 			case 'p':
  414: 				strvalue = va_arg (args, void *);
  415: 				fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
  416: 				break;
  417: 			case 'n':
  418: 				if (cflags == DP_C_SHORT) {
  419: 					short int *num;
  420: 					num = va_arg (args, short int *);
  421: 					*num = currlen;
  422: 				} else if (cflags == DP_C_LONG) {
  423: 					long int *num;
  424: 					num = va_arg (args, long int *);
  425: 					*num = (long int)currlen;
  426: 				} else if (cflags == DP_C_LLONG) {
  427: 					LLONG *num;
  428: 					num = va_arg (args, LLONG *);
  429: 					*num = (LLONG)currlen;
  430: 				} else {
  431: 					int *num;
  432: 					num = va_arg (args, int *);
  433: 					*num = currlen;
  434: 				}
  435: 				break;
  436: 			case '%':
  437: 				dopr_outch (buffer, &currlen, maxlen, ch);
  438: 				break;
  439: 			case 'w':
  440: 				/* not supported yet, treat as next char */
  441: 				ch = *format++;
  442: 				break;
  443: 			default:
  444: 				/* Unknown, skip */
  445: 				break;
  446: 			}
  447: 			ch = *format++;
  448: 			state = DP_S_DEFAULT;
  449: 			flags = cflags = min = 0;
  450: 			max = -1;
  451: 			break;
  452: 		case DP_S_DONE:
  453: 			break;
  454: 		default:
  455: 			/* hmm? */
  456: 			break; /* some picky compilers need this */
  457: 		}
  458: 	}
  459: 	if (maxlen != 0) {
  460: 		if (currlen < maxlen - 1) 
  461: 			buffer[currlen] = '\0';
  462: 		else if (maxlen > 0) 
  463: 			buffer[maxlen - 1] = '\0';
  464: 	}
  465: 	
  466: 	return currlen;
  467: }
  468: 
  469: static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
  470: 		    char *value, int flags, int min, int max)
  471: {
  472: 	int padlen, strln;     /* amount to pad */
  473: 	int cnt = 0;
  474: 
  475: #ifdef DEBUG_SNPRINTF
  476: 	printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
  477: #endif
  478: 	if (value == 0) {
  479: 		value = "<NULL>";
  480: 	}
  481: 
  482: 	for (strln = 0; value[strln]; ++strln); /* strlen */
  483: 	padlen = min - strln;
  484: 	if (padlen < 0) 
  485: 		padlen = 0;
  486: 	if (flags & DP_F_MINUS) 
  487: 		padlen = -padlen; /* Left Justify */
  488: 	
  489: 	while ((padlen > 0) && (cnt < max)) {
  490: 		dopr_outch (buffer, currlen, maxlen, ' ');
  491: 		--padlen;
  492: 		++cnt;
  493: 	}
  494: 	while (*value && (cnt < max)) {
  495: 		dopr_outch (buffer, currlen, maxlen, *value++);
  496: 		++cnt;
  497: 	}
  498: 	while ((padlen < 0) && (cnt < max)) {
  499: 		dopr_outch (buffer, currlen, maxlen, ' ');
  500: 		++padlen;
  501: 		++cnt;
  502: 	}
  503: }
  504: 
  505: /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
  506: 
  507: static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
  508: 		    long value, int base, int min, int max, int flags)
  509: {
  510: 	int signvalue = 0;
  511: 	unsigned long uvalue;
  512: 	char convert[20];
  513: 	int place = 0;
  514: 	int spadlen = 0; /* amount to space pad */
  515: 	int zpadlen = 0; /* amount to zero pad */
  516: 	int caps = 0;
  517: 	
  518: 	if (max < 0)
  519: 		max = 0;
  520: 	
  521: 	uvalue = value;
  522: 	
  523: 	if(!(flags & DP_F_UNSIGNED)) {
  524: 		if( value < 0 ) {
  525: 			signvalue = '-';
  526: 			uvalue = -value;
  527: 		} else {
  528: 			if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
  529: 				signvalue = '+';
  530: 			else if (flags & DP_F_SPACE)
  531: 				signvalue = ' ';
  532: 		}
  533: 	}
  534:   
  535: 	if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
  536: 
  537: 	do {
  538: 		convert[place++] =
  539: 			(caps? "0123456789ABCDEF":"0123456789abcdef")
  540: 			[uvalue % (unsigned)base  ];
  541: 		uvalue = (uvalue / (unsigned)base );
  542: 	} while(uvalue && (place < 20));
  543: 	if (place == 20) place--;
  544: 	convert[place] = 0;
  545: 
  546: 	zpadlen = max - place;
  547: 	spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
  548: 	if (zpadlen < 0) zpadlen = 0;
  549: 	if (spadlen < 0) spadlen = 0;
  550: 	if (flags & DP_F_ZERO) {
  551: 		zpadlen = MAX(zpadlen, spadlen);
  552: 		spadlen = 0;
  553: 	}
  554: 	if (flags & DP_F_MINUS) 
  555: 		spadlen = -spadlen; /* Left Justifty */
  556: 
  557: #ifdef DEBUG_SNPRINTF
  558: 	printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
  559: 	       zpadlen, spadlen, min, max, place);
  560: #endif
  561: 
  562: 	/* Spaces */
  563: 	while (spadlen > 0) {
  564: 		dopr_outch (buffer, currlen, maxlen, ' ');
  565: 		--spadlen;
  566: 	}
  567: 
  568: 	/* Sign */
  569: 	if (signvalue) 
  570: 		dopr_outch (buffer, currlen, maxlen, signvalue);
  571: 
  572: 	/* Zeros */
  573: 	if (zpadlen > 0) {
  574: 		while (zpadlen > 0) {
  575: 			dopr_outch (buffer, currlen, maxlen, '0');
  576: 			--zpadlen;
  577: 		}
  578: 	}
  579: 
  580: 	/* Digits */
  581: 	while (place > 0) 
  582: 		dopr_outch (buffer, currlen, maxlen, convert[--place]);
  583:   
  584: 	/* Left Justified spaces */
  585: 	while (spadlen < 0) {
  586: 		dopr_outch (buffer, currlen, maxlen, ' ');
  587: 		++spadlen;
  588: 	}
  589: }
  590: 
  591: static LDOUBLE abs_val(LDOUBLE value)
  592: {
  593: 	LDOUBLE result = value;
  594: 
  595: 	if (value < 0)
  596: 		result = -value;
  597: 	
  598: 	return result;
  599: }
  600: 
  601: static LDOUBLE POW10(int exp)
  602: {
  603: 	LDOUBLE result = 1;
  604: 	
  605: 	while (exp) {
  606: 		result *= 10;
  607: 		exp--;
  608: 	}
  609:   
  610: 	return result;
  611: }
  612: 
  613: static LLONG ROUND(LDOUBLE value)
  614: {
  615: 	LLONG intpart;
  616: 
  617: 	intpart = (LLONG)value;
  618: 	value = value - intpart;
  619: 	if (value >= 0.5) intpart++;
  620: 	
  621: 	return intpart;
  622: }
  623: 
  624: /* a replacement for modf that doesn't need the math library. Should
  625:    be portable, but slow */
  626: static double my_modf(double x0, double *iptr)
  627: {
  628: 	int i;
  629: 	long l;
  630: 	double x = x0;
  631: 	double f = 1.0;
  632: 
  633: 	for (i=0;i<100;i++) {
  634: 		l = (long)x;
  635: 		if (l <= (x+1) && l >= (x-1)) {
  636: 			if (i != 0) {
  637: 				double i2;
  638: 				double ret;
  639: 
  640: 				ret = my_modf(x0-l*f, &i2);
  641: 				(*iptr) = l*f + i2;
  642: 				return ret;
  643: 			} 
  644: 
  645: 			(*iptr) = l;
  646: 			return x - (*iptr);
  647: 		}
  648: 		x *= 0.1;
  649: 		f *= 10.0;
  650: 	}
  651: 
  652: 	/* yikes! the number is beyond what we can handle. What do we do? */
  653: 	(*iptr) = 0;
  654: 	return 0;
  655: }
  656: 
  657: 
  658: static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
  659: 		   LDOUBLE fvalue, int min, int max, int flags)
  660: {
  661: 	int signvalue = 0;
  662: 	double ufvalue;
  663: 	char iconvert[311];
  664: 	char fconvert[311];
  665: 	int iplace = 0;
  666: 	int fplace = 0;
  667: 	int padlen = 0; /* amount to pad */
  668: 	int zpadlen = 0; 
  669: 	int caps = 0;
  670: 	int idx;
  671: 	double intpart;
  672: 	double fracpart;
  673: 	double temp;
  674:   
  675: 	/* 
  676: 	 * AIX manpage says the default is 0, but Solaris says the default
  677: 	 * is 6, and sprintf on AIX defaults to 6
  678: 	 */
  679: 	if (max < 0)
  680: 		max = 6;
  681: 
  682: 	ufvalue = abs_val (fvalue);
  683: 
  684: 	if (fvalue < 0) {
  685: 		signvalue = '-';
  686: 	} else {
  687: 		if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
  688: 			signvalue = '+';
  689: 		} else {
  690: 			if (flags & DP_F_SPACE)
  691: 				signvalue = ' ';
  692: 		}
  693: 	}
  694: 
  695: #if 0
  696: 	if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
  697: #endif
  698: 
  699: #if 0
  700: 	 if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
  701: #endif
  702: 
  703: 	/* 
  704: 	 * Sorry, we only support 16 digits past the decimal because of our 
  705: 	 * conversion method
  706: 	 */
  707: 	if (max > 16)
  708: 		max = 16;
  709: 
  710: 	/* We "cheat" by converting the fractional part to integer by
  711: 	 * multiplying by a factor of 10
  712: 	 */
  713: 
  714: 	temp = ufvalue;
  715: 	my_modf(temp, &intpart);
  716: 
  717: 	fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
  718: 	
  719: 	if (fracpart >= POW10(max)) {
  720: 		intpart++;
  721: 		fracpart -= POW10(max);
  722: 	}
  723: 
  724: 
  725: 	/* Convert integer part */
  726: 	do {
  727: 		temp = intpart*0.1;
  728: 		my_modf(temp, &intpart);
  729: 		idx = (int) ((temp -intpart +0.05)* 10.0);
  730: 		/* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
  731: 		/* printf ("%llf, %f, %x\n", temp, intpart, idx); */
  732: 		iconvert[iplace++] =
  733: 			(caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
  734: 	} while (intpart && (iplace < 311));
  735: 	if (iplace == 311) iplace--;
  736: 	iconvert[iplace] = 0;
  737: 
  738: 	/* Convert fractional part */
  739: 	if (fracpart)
  740: 	{
  741: 		do {
  742: 			temp = fracpart*0.1;
  743: 			my_modf(temp, &fracpart);
  744: 			idx = (int) ((temp -fracpart +0.05)* 10.0);
  745: 			/* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
  746: 			/* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
  747: 			fconvert[fplace++] =
  748: 			(caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
  749: 		} while(fracpart && (fplace < 311));
  750: 		if (fplace == 311) fplace--;
  751: 	}
  752: 	fconvert[fplace] = 0;
  753:   
  754: 	/* -1 for decimal point, another -1 if we are printing a sign */
  755: 	padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
  756: 	zpadlen = max - fplace;
  757: 	if (zpadlen < 0) zpadlen = 0;
  758: 	if (padlen < 0) 
  759: 		padlen = 0;
  760: 	if (flags & DP_F_MINUS) 
  761: 		padlen = -padlen; /* Left Justifty */
  762: 	
  763: 	if ((flags & DP_F_ZERO) && (padlen > 0)) {
  764: 		if (signvalue) {
  765: 			dopr_outch (buffer, currlen, maxlen, signvalue);
  766: 			--padlen;
  767: 			signvalue = 0;
  768: 		}
  769: 		while (padlen > 0) {
  770: 			dopr_outch (buffer, currlen, maxlen, '0');
  771: 			--padlen;
  772: 		}
  773: 	}
  774: 	while (padlen > 0) {
  775: 		dopr_outch (buffer, currlen, maxlen, ' ');
  776: 		--padlen;
  777: 	}
  778: 	if (signvalue) 
  779: 		dopr_outch (buffer, currlen, maxlen, signvalue);
  780: 	
  781: 	while (iplace > 0) 
  782: 		dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
  783: 
  784: #ifdef DEBUG_SNPRINTF
  785: 	printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
  786: #endif
  787: 
  788: 	/*
  789: 	 * Decimal point.  This should probably use locale to find the correct
  790: 	 * char to print out.
  791: 	 */
  792: 	if (max > 0) {
  793: 		dopr_outch (buffer, currlen, maxlen, '.');
  794: 		
  795: 		while (zpadlen > 0) {
  796: 			dopr_outch (buffer, currlen, maxlen, '0');
  797: 			--zpadlen;
  798: 		}
  799: 
  800: 		while (fplace > 0) 
  801: 			dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
  802: 	}
  803: 
  804: 	while (padlen < 0) {
  805: 		dopr_outch (buffer, currlen, maxlen, ' ');
  806: 		++padlen;
  807: 	}
  808: }
  809: 
  810: static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
  811: {
  812: 	if (*currlen < maxlen) {
  813: 		buffer[(*currlen)] = c;
  814: 	}
  815: 	(*currlen)++;
  816: }
  817: 
  818:  int rsync_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
  819: {
  820: 	return dopr(str, count, fmt, args);
  821: }
  822: #define vsnprintf rsync_vsnprintf
  823: #endif
  824: 
  825: /* yes this really must be a ||. Don't muck with this (tridge)
  826:  *
  827:  * The logic for these two is that we need our own definition if the
  828:  * OS *either* has no definition of *sprintf, or if it does have one
  829:  * that doesn't work properly according to the autoconf test.
  830:  */
  831: #if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
  832: int rsync_snprintf(char *str,size_t count,const char *fmt,...)
  833: {
  834: 	size_t ret;
  835: 	va_list ap;
  836:     
  837: 	va_start(ap, fmt);
  838: 	ret = vsnprintf(str, count, fmt, ap);
  839: 	va_end(ap);
  840: 	return ret;
  841: }
  842: #define snprintf rsync_snprintf
  843: #endif
  844: 
  845: #endif 
  846: 
  847: #ifndef HAVE_VASPRINTF
  848:  int vasprintf(char **ptr, const char *format, va_list ap)
  849: {
  850: 	int ret;
  851: 	va_list ap2;
  852: 
  853: 	VA_COPY(ap2, ap);
  854: 	
  855: 	ret = vsnprintf(NULL, 0, format, ap2);
  856: 	if (ret <= 0) return ret;
  857: 
  858: 	(*ptr) = (char *)malloc(ret+1);
  859: 	if (!*ptr) return -1;
  860: 
  861: 	VA_COPY(ap2, ap);
  862: 
  863: 	ret = vsnprintf(*ptr, ret+1, format, ap2);
  864: 
  865: 	return ret;
  866: }
  867: #endif
  868: 
  869: 
  870: #ifndef HAVE_ASPRINTF
  871:  int asprintf(char **ptr, const char *format, ...)
  872: {
  873: 	va_list ap;
  874: 	int ret;
  875: 	
  876: 	*ptr = NULL;
  877: 	va_start(ap, format);
  878: 	ret = vasprintf(ptr, format, ap);
  879: 	va_end(ap);
  880: 
  881: 	return ret;
  882: }
  883: #endif
  884: 
  885: #ifdef TEST_SNPRINTF
  886: 
  887:  int sprintf(char *str,const char *fmt,...);
  888: 
  889:  int main (void)
  890: {
  891: 	char buf1[1024];
  892: 	char buf2[1024];
  893: 	char *fp_fmt[] = {
  894: 		"%1.1f",
  895: 		"%-1.5f",
  896: 		"%1.5f",
  897: 		"%123.9f",
  898: 		"%10.5f",
  899: 		"% 10.5f",
  900: 		"%+22.9f",
  901: 		"%+4.9f",
  902: 		"%01.3f",
  903: 		"%4f",
  904: 		"%3.1f",
  905: 		"%3.2f",
  906: 		"%.0f",
  907: 		"%f",
  908: 		"-16.16f",
  909: 		NULL
  910: 	};
  911: 	double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996, 
  912: 			     0.9996, 1.996, 4.136, 5.030201, 0.00205,
  913: 			     /* END LIST */ 0};
  914: 	char *int_fmt[] = {
  915: 		"%-1.5d",
  916: 		"%1.5d",
  917: 		"%123.9d",
  918: 		"%5.5d",
  919: 		"%10.5d",
  920: 		"% 10.5d",
  921: 		"%+22.33d",
  922: 		"%01.3d",
  923: 		"%4d",
  924: 		"%d",
  925: 		NULL
  926: 	};
  927: 	long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
  928: 	char *str_fmt[] = {
  929: 		"10.5s",
  930: 		"5.10s",
  931: 		"10.1s",
  932: 		"0.10s",
  933: 		"10.0s",
  934: 		"1.10s",
  935: 		"%s",
  936: 		"%.1s",
  937: 		"%.10s",
  938: 		"%10s",
  939: 		NULL
  940: 	};
  941: 	char *str_vals[] = {"hello", "a", "", "a longer string", NULL};
  942: 	int x, y;
  943: 	int fail = 0;
  944: 	int num = 0;
  945: 
  946: 	printf ("Testing snprintf format codes against system sprintf...\n");
  947: 
  948: 	for (x = 0; fp_fmt[x] ; x++) {
  949: 		for (y = 0; fp_nums[y] != 0 ; y++) {
  950: 			int l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]);
  951: 			int l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
  952: 			sprintf (buf2, fp_fmt[x], fp_nums[y]);
  953: 			if (strcmp (buf1, buf2)) {
  954: 				printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", 
  955: 				       fp_fmt[x], buf1, buf2);
  956: 				fail++;
  957: 			}
  958: 			if (l1 != l2) {
  959: 				printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, fp_fmt[x]);
  960: 				fail++;
  961: 			}
  962: 			num++;
  963: 		}
  964: 	}
  965: 
  966: 	for (x = 0; int_fmt[x] ; x++) {
  967: 		for (y = 0; int_nums[y] != 0 ; y++) {
  968: 			int l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]);
  969: 			int l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
  970: 			sprintf (buf2, int_fmt[x], int_nums[y]);
  971: 			if (strcmp (buf1, buf2)) {
  972: 				printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", 
  973: 				       int_fmt[x], buf1, buf2);
  974: 				fail++;
  975: 			}
  976: 			if (l1 != l2) {
  977: 				printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, int_fmt[x]);
  978: 				fail++;
  979: 			}
  980: 			num++;
  981: 		}
  982: 	}
  983: 
  984: 	for (x = 0; str_fmt[x] ; x++) {
  985: 		for (y = 0; str_vals[y] != 0 ; y++) {
  986: 			int l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]);
  987: 			int l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
  988: 			sprintf (buf2, str_fmt[x], str_vals[y]);
  989: 			if (strcmp (buf1, buf2)) {
  990: 				printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", 
  991: 				       str_fmt[x], buf1, buf2);
  992: 				fail++;
  993: 			}
  994: 			if (l1 != l2) {
  995: 				printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, str_fmt[x]);
  996: 				fail++;
  997: 			}
  998: 			num++;
  999: 		}
 1000: 	}
 1001: 
 1002: 	printf ("%d tests failed out of %d.\n", fail, num);
 1003: 
 1004: 	printf("seeing how many digits we support\n");
 1005: 	{
 1006: 		double v0 = 0.12345678901234567890123456789012345678901;
 1007: 		for (x=0; x<100; x++) {
 1008: 			double p = pow(10, x); 
 1009: 			double r = v0*p;
 1010: 			snprintf(buf1, sizeof(buf1), "%1.1f", r);
 1011: 			sprintf(buf2,                "%1.1f", r);
 1012: 			if (strcmp(buf1, buf2)) {
 1013: 				printf("we seem to support %d digits\n", x-1);
 1014: 				break;
 1015: 			}
 1016: 		}
 1017: 	}
 1018: 
 1019: 	return 0;
 1020: }
 1021: #endif /* TEST_SNPRINTF */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>