File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / lib / snprintf.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:32:36 2021 UTC (3 years, 5 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_2_3, HEAD
rsync 3.2.3

    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, formatted 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 -I.. -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:  * added 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:  * Darren Tucker (dtucker@zip.com.au) 2005
   94:  *    Fix bug allowing read overruns of the source string with "%.*s"
   95:  *    Usually harmless unless the read runs outside the process' allocation
   96:  *    (eg if your malloc does guard pages) in which case it will segfault.
   97:  *    From OpenSSH.  Also added test for same.
   98:  *
   99:  * Simo Sorce (idra@samba.org) Jan 2006
  100:  * 
  101:  *    Add support for position independent parameters 
  102:  *    fix fmtstr now it conforms to sprintf wrt min.max
  103:  *
  104:  **************************************************************/
  105: 
  106: #include "config.h"
  107: 
  108: #ifdef TEST_SNPRINTF /* need math library headers for testing */
  109: 
  110: /* In test mode, we pretend that this system doesn't have any snprintf
  111:  * functions, regardless of what config.h says. */
  112: #  undef HAVE_SNPRINTF
  113: #  undef HAVE_VSNPRINTF
  114: #  undef HAVE_C99_VSNPRINTF
  115: #  undef HAVE_ASPRINTF
  116: #  undef HAVE_VASPRINTF
  117: #  include <math.h>
  118: #endif /* TEST_SNPRINTF */
  119: 
  120: #ifdef HAVE_STRING_H
  121: #include <string.h>
  122: #endif
  123: 
  124: #ifdef HAVE_STRINGS_H
  125: #include <strings.h>
  126: #endif
  127: #ifdef HAVE_CTYPE_H
  128: #include <ctype.h>
  129: #endif
  130: #include <sys/types.h>
  131: #include <stdarg.h>
  132: #ifdef HAVE_STDLIB_H
  133: #include <stdlib.h>
  134: #endif
  135: 
  136: #if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)
  137: /* only include stdio.h if we are not re-defining snprintf or vsnprintf */
  138: #include <stdio.h>
  139:  /* make the compiler happy with an empty file */
  140:  void dummy_snprintf(void);
  141:  void dummy_snprintf(void) {} 
  142: #endif /* HAVE_SNPRINTF, etc */
  143: 
  144: #ifdef STDC_HEADERS
  145: #include <stddef.h>
  146: #endif
  147: 
  148: #ifdef HAVE_LONG_DOUBLE
  149: #define LDOUBLE long double
  150: #else
  151: #define LDOUBLE double
  152: #endif
  153: 
  154: #if !defined HAVE_LONG_LONG && SIZEOF_LONG_LONG
  155: #define HAVE_LONG_LONG 1
  156: #endif
  157: #ifdef HAVE_LONG_LONG
  158: #define LLONG long long
  159: #else
  160: #define LLONG long
  161: #endif
  162: 
  163: #ifndef VA_COPY
  164: #if defined HAVE_VA_COPY || defined va_copy
  165: #define VA_COPY(dest, src) va_copy(dest, src)
  166: #else
  167: #ifdef HAVE___VA_COPY
  168: #define VA_COPY(dest, src) __va_copy(dest, src)
  169: #else
  170: #define VA_COPY(dest, src) (dest) = (src)
  171: #endif
  172: #endif
  173: #endif
  174: 
  175: /* yes this really must be a ||. Don't muck with this (tridge) */
  176: #if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
  177: 
  178: /*
  179:  * dopr(): poor man's version of doprintf
  180:  */
  181: 
  182: /* format read states */
  183: #define DP_S_DEFAULT 0
  184: #define DP_S_FLAGS   1
  185: #define DP_S_MIN     2
  186: #define DP_S_DOT     3
  187: #define DP_S_MAX     4
  188: #define DP_S_MOD     5
  189: #define DP_S_CONV    6
  190: #define DP_S_DONE    7
  191: 
  192: /* format flags - Bits */
  193: #define DP_F_MINUS 	(1 << 0)
  194: #define DP_F_PLUS  	(1 << 1)
  195: #define DP_F_SPACE 	(1 << 2)
  196: #define DP_F_NUM   	(1 << 3)
  197: #define DP_F_ZERO  	(1 << 4)
  198: #define DP_F_UP    	(1 << 5)
  199: #define DP_F_UNSIGNED 	(1 << 6)
  200: 
  201: /* Conversion Flags */
  202: #define DP_C_CHAR    1
  203: #define DP_C_SHORT   2
  204: #define DP_C_LONG    3
  205: #define DP_C_LDOUBLE 4
  206: #define DP_C_LLONG   5
  207: #define DP_C_SIZET   6
  208: 
  209: /* Chunk types */
  210: #define CNK_FMT_STR 0
  211: #define CNK_INT     1
  212: #define CNK_OCTAL   2
  213: #define CNK_UINT    3
  214: #define CNK_HEX     4
  215: #define CNK_FLOAT   5
  216: #define CNK_CHAR    6
  217: #define CNK_STRING  7
  218: #define CNK_PTR     8
  219: #define CNK_NUM     9
  220: #define CNK_PRCNT   10
  221: 
  222: #define char_to_int(p) ((p)- '0')
  223: #ifndef MAX
  224: #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
  225: #endif
  226: 
  227: struct pr_chunk {
  228: 	int type; /* chunk type */
  229: 	int num; /* parameter number */
  230: 	int min; 
  231: 	int max;
  232: 	int flags;
  233: 	int cflags;
  234: 	int start;
  235: 	int len;
  236: 	LLONG value;
  237: 	LDOUBLE fvalue;
  238: 	char *strvalue;
  239: 	void *pnum;
  240: 	struct pr_chunk *min_star;
  241: 	struct pr_chunk *max_star;
  242: 	struct pr_chunk *next;
  243: };
  244: 
  245: struct pr_chunk_x {
  246: 	struct pr_chunk **chunks;
  247: 	int num;
  248: };
  249: 
  250: static int dopr(char *buffer, size_t maxlen, const char *format, 
  251: 		   va_list args_in);
  252: static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
  253: 		    char *value, int flags, int min, int max);
  254: static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
  255: 		    LLONG value, int base, int min, int max, int flags);
  256: static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
  257: 		   LDOUBLE fvalue, int min, int max, int flags);
  258: static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
  259: static struct pr_chunk *new_chunk(void);
  260: static int add_cnk_list_entry(struct pr_chunk_x **list,
  261: 				int max_num, struct pr_chunk *chunk);
  262: 
  263: static int dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
  264: {
  265: 	char ch;
  266: 	int state;
  267: 	int pflag;
  268: 	int pnum;
  269: 	int pfirst;
  270: 	size_t currlen;
  271: 	va_list args;
  272: 	const char *base;
  273: 	struct pr_chunk *chunks = NULL;
  274: 	struct pr_chunk *cnk = NULL;
  275: 	struct pr_chunk_x *clist = NULL;
  276: 	int max_pos;
  277: 	int ret = -1;
  278: 
  279: 	VA_COPY(args, args_in);
  280: 
  281: 	state = DP_S_DEFAULT;
  282: 	pfirst = 1;
  283: 	pflag = 0;
  284: 	pnum = 0;
  285: 
  286: 	max_pos = 0;
  287: 	base = format;
  288: 	ch = *format++;
  289: 	
  290: 	/* retrieve the string structure as chunks */
  291: 	while (state != DP_S_DONE) {
  292: 		if (ch == '\0') 
  293: 			state = DP_S_DONE;
  294: 
  295: 		switch(state) {
  296: 		case DP_S_DEFAULT:
  297: 			
  298: 			if (cnk) {
  299: 				cnk->next = new_chunk();
  300: 				cnk = cnk->next;
  301: 			} else {
  302: 				cnk = new_chunk();
  303: 			}
  304: 			if (!cnk) goto done;
  305: 			if (!chunks) chunks = cnk;
  306: 			
  307: 			if (ch == '%') {
  308: 				state = DP_S_FLAGS;
  309: 				ch = *format++;
  310: 			} else {
  311: 				cnk->type = CNK_FMT_STR;
  312: 				cnk->start = format - base -1;
  313: 				while ((ch != '\0') && (ch != '%')) ch = *format++;
  314: 				cnk->len = format - base - cnk->start -1;
  315: 			}
  316: 			break;
  317: 		case DP_S_FLAGS:
  318: 			switch (ch) {
  319: 			case '-':
  320: 				cnk->flags |= DP_F_MINUS;
  321: 				ch = *format++;
  322: 				break;
  323: 			case '+':
  324: 				cnk->flags |= DP_F_PLUS;
  325: 				ch = *format++;
  326: 				break;
  327: 			case ' ':
  328: 				cnk->flags |= DP_F_SPACE;
  329: 				ch = *format++;
  330: 				break;
  331: 			case '#':
  332: 				cnk->flags |= DP_F_NUM;
  333: 				ch = *format++;
  334: 				break;
  335: 			case '0':
  336: 				cnk->flags |= DP_F_ZERO;
  337: 				ch = *format++;
  338: 				break;
  339: 			case 'I':
  340: 				/* internationalization not supported yet */
  341: 				ch = *format++;
  342: 				break;
  343: 			default:
  344: 				state = DP_S_MIN;
  345: 				break;
  346: 			}
  347: 			break;
  348: 		case DP_S_MIN:
  349: 			if (isdigit((unsigned char)ch)) {
  350: 				cnk->min = 10 * cnk->min + char_to_int (ch);
  351: 				ch = *format++;
  352: 			} else if (ch == '$') {
  353: 				if (!pfirst && !pflag) {
  354: 					/* parameters must be all positioned or none */
  355: 					goto done;
  356: 				}
  357: 				if (pfirst) {
  358: 					pfirst = 0;
  359: 					pflag = 1;
  360: 				}
  361: 				if (cnk->min == 0) /* what ?? */
  362: 					goto done;
  363: 				cnk->num = cnk->min;
  364: 				cnk->min = 0;
  365: 				ch = *format++;
  366: 			} else if (ch == '*') {
  367: 				if (pfirst) pfirst = 0;
  368: 				cnk->min_star = new_chunk();
  369: 				if (!cnk->min_star) /* out of memory :-( */
  370: 					goto done;
  371: 				cnk->min_star->type = CNK_INT;
  372: 				if (pflag) {
  373: 					int num;
  374: 					ch = *format++;
  375: 					if (!isdigit((unsigned char)ch)) {
  376: 						/* parameters must be all positioned or none */
  377: 						goto done;
  378: 					}
  379: 					for (num = 0; isdigit((unsigned char)ch); ch = *format++) {
  380: 						num = 10 * num + char_to_int(ch);
  381: 					}
  382: 					cnk->min_star->num = num;
  383: 					if (ch != '$') /* what ?? */
  384: 						goto done;
  385: 				} else {
  386: 					cnk->min_star->num = ++pnum;
  387: 				}
  388: 				max_pos = add_cnk_list_entry(&clist, max_pos, cnk->min_star);
  389: 				if (max_pos == 0) /* out of memory :-( */
  390: 					goto done;
  391: 				ch = *format++;
  392: 				state = DP_S_DOT;
  393: 			} else {
  394: 				if (pfirst) pfirst = 0;
  395: 				state = DP_S_DOT;
  396: 			}
  397: 			break;
  398: 		case DP_S_DOT:
  399: 			if (ch == '.') {
  400: 				state = DP_S_MAX;
  401: 				ch = *format++;
  402: 			} else { 
  403: 				state = DP_S_MOD;
  404: 			}
  405: 			break;
  406: 		case DP_S_MAX:
  407: 			if (isdigit((unsigned char)ch)) {
  408: 				if (cnk->max < 0)
  409: 					cnk->max = 0;
  410: 				cnk->max = 10 * cnk->max + char_to_int (ch);
  411: 				ch = *format++;
  412: 			} else if (ch == '$') {
  413: 				if (!pfirst && !pflag) {
  414: 					/* parameters must be all positioned or none */
  415: 					goto done;
  416: 				}
  417: 				if (cnk->max <= 0) /* what ?? */
  418: 					goto done;
  419: 				cnk->num = cnk->max;
  420: 				cnk->max = -1;
  421: 				ch = *format++;
  422: 			} else if (ch == '*') {
  423: 				cnk->max_star = new_chunk();
  424: 				if (!cnk->max_star) /* out of memory :-( */
  425: 					goto done;
  426: 				cnk->max_star->type = CNK_INT;
  427: 				if (pflag) {
  428: 					int num;
  429: 					ch = *format++;
  430: 					if (!isdigit((unsigned char)ch)) {
  431: 						/* parameters must be all positioned or none */
  432: 						goto done;
  433: 					}
  434: 					for (num = 0; isdigit((unsigned char)ch); ch = *format++) {
  435: 						num = 10 * num + char_to_int(ch);
  436: 					}
  437: 					cnk->max_star->num = num;
  438: 					if (ch != '$') /* what ?? */
  439: 						goto done;
  440: 				} else {
  441: 					cnk->max_star->num = ++pnum;
  442: 				}
  443: 				max_pos = add_cnk_list_entry(&clist, max_pos, cnk->max_star);
  444: 				if (max_pos == 0) /* out of memory :-( */
  445: 					goto done;
  446: 
  447: 				ch = *format++;
  448: 				state = DP_S_MOD;
  449: 			} else {
  450: 				state = DP_S_MOD;
  451: 			}
  452: 			break;
  453: 		case DP_S_MOD:
  454: 			switch (ch) {
  455: 			case 'h':
  456: 				cnk->cflags = DP_C_SHORT;
  457: 				ch = *format++;
  458: 				if (ch == 'h') {
  459: 					cnk->cflags = DP_C_CHAR;
  460: 					ch = *format++;
  461: 				}
  462: 				break;
  463: 			case 'l':
  464: 				cnk->cflags = DP_C_LONG;
  465: 				ch = *format++;
  466: 				if (ch == 'l') {	/* It's a long long */
  467: 					cnk->cflags = DP_C_LLONG;
  468: 					ch = *format++;
  469: 				}
  470: 				break;
  471: 			case 'L':
  472: 				cnk->cflags = DP_C_LDOUBLE;
  473: 				ch = *format++;
  474: 				break;
  475: 			case 'z':
  476: 				cnk->cflags = DP_C_SIZET;
  477: 				ch = *format++;
  478: 				break;
  479: 			default:
  480: 				break;
  481: 			}
  482: 			state = DP_S_CONV;
  483: 			break;
  484: 		case DP_S_CONV:
  485: 			if (cnk->num == 0) cnk->num = ++pnum;
  486: 			max_pos = add_cnk_list_entry(&clist, max_pos, cnk);
  487: 			if (max_pos == 0) /* out of memory :-( */
  488: 				goto done;
  489: 			
  490: 			switch (ch) {
  491: 			case 'd':
  492: 			case 'i':
  493: 				cnk->type = CNK_INT;
  494: 				break;
  495: 			case 'o':
  496: 				cnk->type = CNK_OCTAL;
  497: 				cnk->flags |= DP_F_UNSIGNED;
  498: 				break;
  499: 			case 'u':
  500: 				cnk->type = CNK_UINT;
  501: 				cnk->flags |= DP_F_UNSIGNED;
  502: 				break;
  503: 			case 'X':
  504: 				cnk->flags |= DP_F_UP;
  505: 			case 'x':
  506: 				cnk->type = CNK_HEX;
  507: 				cnk->flags |= DP_F_UNSIGNED;
  508: 				break;
  509: 			case 'A':
  510: 				/* hex float not supported yet */
  511: 			case 'E':
  512: 			case 'G':
  513: 			case 'F':
  514: 				cnk->flags |= DP_F_UP;
  515: 			case 'a':
  516: 				/* hex float not supported yet */
  517: 			case 'e':
  518: 			case 'f':
  519: 			case 'g':
  520: 				cnk->type = CNK_FLOAT;
  521: 				break;
  522: 			case 'c':
  523: 				cnk->type = CNK_CHAR;
  524: 				break;
  525: 			case 's':
  526: 				cnk->type = CNK_STRING;
  527: 				break;
  528: 			case 'p':
  529: 				cnk->type = CNK_PTR;
  530: 				cnk->flags |= DP_F_UNSIGNED;
  531: 				break;
  532: 			case 'n':
  533: 				cnk->type = CNK_NUM;
  534: 				break;
  535: 			case '%':
  536: 				cnk->type = CNK_PRCNT;
  537: 				break;
  538: 			default:
  539: 				/* Unknown, bail out*/
  540: 				goto done;
  541: 			}
  542: 			ch = *format++;
  543: 			state = DP_S_DEFAULT;
  544: 			break;
  545: 		case DP_S_DONE:
  546: 			break;
  547: 		default:
  548: 			/* hmm? */
  549: 			break; /* some picky compilers need this */
  550: 		}
  551: 	}
  552: 
  553: 	/* retrieve the format arguments */
  554: 	for (pnum = 0; pnum < max_pos; pnum++) {
  555: 		int i;
  556: 
  557: 		if (clist[pnum].num == 0) {
  558: 			/* ignoring a parameter should not be permitted
  559: 			 * all parameters must be matched at least once
  560: 			 * BUT seem some system ignore this rule ...
  561: 			 * at least my glibc based system does --SSS
  562: 			 */
  563: #ifdef DEBUG_SNPRINTF
  564: 			printf("parameter at position %d not used\n", pnum+1);
  565: #endif
  566: 			/* eat the parameter */
  567: 			va_arg (args, int);
  568: 			continue;
  569: 		}
  570: 		for (i = 1; i < clist[pnum].num; i++) {
  571: 			if (clist[pnum].chunks[0]->type != clist[pnum].chunks[i]->type) {
  572: 				/* nooo noo no!
  573: 				 * all the references to a parameter
  574: 				 * must be of the same type
  575: 				 */
  576: 				goto done;
  577: 			}
  578: 		}
  579: 		cnk = clist[pnum].chunks[0];
  580: 		switch (cnk->type) {
  581: 		case CNK_INT:
  582: 			if (cnk->cflags == DP_C_SHORT) 
  583: 				cnk->value = va_arg (args, int);
  584: 			else if (cnk->cflags == DP_C_LONG)
  585: 				cnk->value = va_arg (args, long int);
  586: 			else if (cnk->cflags == DP_C_LLONG)
  587: 				cnk->value = va_arg (args, LLONG);
  588: 			else if (cnk->cflags == DP_C_SIZET)
  589: 				cnk->value = va_arg (args, ssize_t);
  590: 			else
  591: 				cnk->value = va_arg (args, int);
  592: 
  593: 			for (i = 1; i < clist[pnum].num; i++) {
  594: 				clist[pnum].chunks[i]->value = cnk->value;
  595: 			}
  596: 			break;
  597: 
  598: 		case CNK_OCTAL:
  599: 		case CNK_UINT:
  600: 		case CNK_HEX:
  601: 			if (cnk->cflags == DP_C_SHORT)
  602: 				cnk->value = va_arg (args, unsigned int);
  603: 			else if (cnk->cflags == DP_C_LONG)
  604: 				cnk->value = (unsigned long int)va_arg (args, unsigned long int);
  605: 			else if (cnk->cflags == DP_C_LLONG)
  606: 				cnk->value = (LLONG)va_arg (args, unsigned LLONG);
  607: 			else if (cnk->cflags == DP_C_SIZET)
  608: 				cnk->value = (size_t)va_arg (args, size_t);
  609: 			else
  610: 				cnk->value = (unsigned int)va_arg (args, unsigned int);
  611: 
  612: 			for (i = 1; i < clist[pnum].num; i++) {
  613: 				clist[pnum].chunks[i]->value = cnk->value;
  614: 			}
  615: 			break;
  616: 
  617: 		case CNK_FLOAT:
  618: 			if (cnk->cflags == DP_C_LDOUBLE)
  619: 				cnk->fvalue = va_arg (args, LDOUBLE);
  620: 			else
  621: 				cnk->fvalue = va_arg (args, double);
  622: 
  623: 			for (i = 1; i < clist[pnum].num; i++) {
  624: 				clist[pnum].chunks[i]->fvalue = cnk->fvalue;
  625: 			}
  626: 			break;
  627: 
  628: 		case CNK_CHAR:
  629: 			cnk->value = va_arg (args, int);
  630: 
  631: 			for (i = 1; i < clist[pnum].num; i++) {
  632: 				clist[pnum].chunks[i]->value = cnk->value;
  633: 			}
  634: 			break;
  635: 
  636: 		case CNK_STRING:
  637: 			cnk->strvalue = va_arg (args, char *);
  638: 			if (!cnk->strvalue) cnk->strvalue = "(NULL)";
  639: 
  640: 			for (i = 1; i < clist[pnum].num; i++) {
  641: 				clist[pnum].chunks[i]->strvalue = cnk->strvalue;
  642: 			}
  643: 			break;
  644: 
  645: 		case CNK_PTR:
  646: 			cnk->strvalue = va_arg (args, void *);
  647: 			for (i = 1; i < clist[pnum].num; i++) {
  648: 				clist[pnum].chunks[i]->strvalue = cnk->strvalue;
  649: 			}
  650: 			break;
  651: 
  652: 		case CNK_NUM:
  653: 			if (cnk->cflags == DP_C_CHAR)
  654: 				cnk->pnum = va_arg (args, char *);
  655: 			else if (cnk->cflags == DP_C_SHORT)
  656: 				cnk->pnum = va_arg (args, short int *);
  657: 			else if (cnk->cflags == DP_C_LONG)
  658: 				cnk->pnum = va_arg (args, long int *);
  659: 			else if (cnk->cflags == DP_C_LLONG)
  660: 				cnk->pnum = va_arg (args, LLONG *);
  661: 			else if (cnk->cflags == DP_C_SIZET)
  662: 				cnk->pnum = va_arg (args, ssize_t *);
  663: 			else
  664: 				cnk->pnum = va_arg (args, int *);
  665: 
  666: 			for (i = 1; i < clist[pnum].num; i++) {
  667: 				clist[pnum].chunks[i]->pnum = cnk->pnum;
  668: 			}
  669: 			break;
  670: 
  671: 		case CNK_PRCNT:
  672: 			break;
  673: 
  674: 		default:
  675: 			/* what ?? */
  676: 			goto done;
  677: 		}
  678: 	}
  679: 	/* print out the actual string from chunks */
  680: 	currlen = 0;
  681: 	cnk = chunks;
  682: 	while (cnk) {
  683: 		int len, min, max;
  684: 
  685: 		if (cnk->min_star) min = cnk->min_star->value;
  686: 		else min = cnk->min;
  687: 		if (cnk->max_star) max = cnk->max_star->value;
  688: 		else max = cnk->max;
  689: 
  690: 		switch (cnk->type) {
  691: 
  692: 		case CNK_FMT_STR:
  693: 			if (maxlen != 0 && maxlen > currlen) {
  694: 				if (maxlen > (currlen + cnk->len)) len = cnk->len;
  695: 				else len = maxlen - currlen;
  696: 
  697: 				memcpy(&(buffer[currlen]), &(base[cnk->start]), len);
  698: 			}
  699: 			currlen += cnk->len;
  700: 				
  701: 			break;
  702: 
  703: 		case CNK_INT:
  704: 		case CNK_UINT:
  705: 			fmtint (buffer, &currlen, maxlen, cnk->value, 10, min, max, cnk->flags);
  706: 			break;
  707: 
  708: 		case CNK_OCTAL:
  709: 			fmtint (buffer, &currlen, maxlen, cnk->value, 8, min, max, cnk->flags);
  710: 			break;
  711: 
  712: 		case CNK_HEX:
  713: 			fmtint (buffer, &currlen, maxlen, cnk->value, 16, min, max, cnk->flags);
  714: 			break;
  715: 
  716: 		case CNK_FLOAT:
  717: 			fmtfp (buffer, &currlen, maxlen, cnk->fvalue, min, max, cnk->flags);
  718: 			break;
  719: 
  720: 		case CNK_CHAR:
  721: 			dopr_outch (buffer, &currlen, maxlen, cnk->value);
  722: 			break;
  723: 
  724: 		case CNK_STRING:
  725: 			if (max == -1) {
  726: 				max = strlen(cnk->strvalue);
  727: 			}
  728: 			fmtstr (buffer, &currlen, maxlen, cnk->strvalue, cnk->flags, min, max);
  729: 			break;
  730: 
  731: 		case CNK_PTR:
  732: 			fmtint (buffer, &currlen, maxlen, (long)(cnk->strvalue), 16, min, max, cnk->flags);
  733: 			break;
  734: 
  735: 		case CNK_NUM:
  736: 			if (cnk->cflags == DP_C_CHAR)
  737: 				*((char *)(cnk->pnum)) = (char)currlen;
  738: 			else if (cnk->cflags == DP_C_SHORT)
  739: 				*((short int *)(cnk->pnum)) = (short int)currlen;
  740: 			else if (cnk->cflags == DP_C_LONG)
  741: 				*((long int *)(cnk->pnum)) = (long int)currlen;
  742: 			else if (cnk->cflags == DP_C_LLONG)
  743: 				*((LLONG *)(cnk->pnum)) = (LLONG)currlen;
  744: 			else if (cnk->cflags == DP_C_SIZET)
  745: 				*((ssize_t *)(cnk->pnum)) = (ssize_t)currlen;
  746: 			else
  747: 				*((int *)(cnk->pnum)) = (int)currlen;
  748: 			break;
  749: 
  750: 		case CNK_PRCNT:
  751: 			dopr_outch (buffer, &currlen, maxlen, '%');
  752: 			break;
  753: 
  754: 		default:
  755: 			/* what ?? */
  756: 			goto done;
  757: 		}
  758: 		cnk = cnk->next;
  759: 	}
  760: 	if (maxlen != 0) {
  761: 		if (currlen < maxlen - 1) 
  762: 			buffer[currlen] = '\0';
  763: 		else if (maxlen > 0) 
  764: 			buffer[maxlen - 1] = '\0';
  765: 	}
  766: 	ret = currlen;
  767: 
  768: done:
  769: 	va_end(args);
  770: 
  771: 	while (chunks) {
  772: 		cnk = chunks->next;
  773: 		free(chunks);
  774: 		chunks = cnk;
  775: 	}
  776: 	if (clist) {
  777: 		for (pnum = 0; pnum < max_pos; pnum++) {
  778: 			if (clist[pnum].chunks) free(clist[pnum].chunks);
  779: 		}
  780: 		free(clist);
  781: 	}
  782: 	return ret;
  783: }
  784: 
  785: static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
  786: 		    char *value, int flags, int min, int max)
  787: {
  788: 	int padlen, strln;     /* amount to pad */
  789: 	int cnt = 0;
  790: 
  791: #ifdef DEBUG_SNPRINTF
  792: 	printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
  793: #endif
  794: 	if (value == 0) {
  795: 		value = "<NULL>";
  796: 	}
  797: 
  798: 	for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */
  799: 	padlen = min - strln;
  800: 	if (padlen < 0) 
  801: 		padlen = 0;
  802: 	if (flags & DP_F_MINUS) 
  803: 		padlen = -padlen; /* Left Justify */
  804: 	
  805: 	while (padlen > 0) {
  806: 		dopr_outch (buffer, currlen, maxlen, ' ');
  807: 		--padlen;
  808: 	}
  809: 	while (*value && (cnt < max)) {
  810: 		dopr_outch (buffer, currlen, maxlen, *value++);
  811: 		++cnt;
  812: 	}
  813: 	while (padlen < 0) {
  814: 		dopr_outch (buffer, currlen, maxlen, ' ');
  815: 		++padlen;
  816: 	}
  817: }
  818: 
  819: /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
  820: 
  821: static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
  822: 		    LLONG value, int base, int min, int max, int flags)
  823: {
  824: 	int signvalue = 0;
  825: 	unsigned LLONG uvalue;
  826: 	char convert[20];
  827: 	int place = 0;
  828: 	int spadlen = 0; /* amount to space pad */
  829: 	int zpadlen = 0; /* amount to zero pad */
  830: 	int caps = 0;
  831: 	
  832: 	if (max < 0)
  833: 		max = 0;
  834: 	
  835: 	uvalue = value;
  836: 	
  837: 	if(!(flags & DP_F_UNSIGNED)) {
  838: 		if( value < 0 ) {
  839: 			signvalue = '-';
  840: 			uvalue = -value;
  841: 		} else {
  842: 			if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
  843: 				signvalue = '+';
  844: 			else if (flags & DP_F_SPACE)
  845: 				signvalue = ' ';
  846: 		}
  847: 	}
  848:   
  849: 	if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
  850: 
  851: 	do {
  852: 		convert[place++] =
  853: 			(caps? "0123456789ABCDEF":"0123456789abcdef")
  854: 			[uvalue % (unsigned)base  ];
  855: 		uvalue = (uvalue / (unsigned)base );
  856: 	} while(uvalue && (place < 20));
  857: 	if (place == 20) place--;
  858: 	convert[place] = 0;
  859: 
  860: 	zpadlen = max - place;
  861: 	spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
  862: 	if (zpadlen < 0) zpadlen = 0;
  863: 	if (spadlen < 0) spadlen = 0;
  864: 	if (flags & DP_F_ZERO) {
  865: 		zpadlen = MAX(zpadlen, spadlen);
  866: 		spadlen = 0;
  867: 	}
  868: 	if (flags & DP_F_MINUS) 
  869: 		spadlen = -spadlen; /* Left Justifty */
  870: 
  871: #ifdef DEBUG_SNPRINTF
  872: 	printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
  873: 	       zpadlen, spadlen, min, max, place);
  874: #endif
  875: 
  876: 	/* Spaces */
  877: 	while (spadlen > 0) {
  878: 		dopr_outch (buffer, currlen, maxlen, ' ');
  879: 		--spadlen;
  880: 	}
  881: 
  882: 	/* Sign */
  883: 	if (signvalue) 
  884: 		dopr_outch (buffer, currlen, maxlen, signvalue);
  885: 
  886: 	/* Zeros */
  887: 	if (zpadlen > 0) {
  888: 		while (zpadlen > 0) {
  889: 			dopr_outch (buffer, currlen, maxlen, '0');
  890: 			--zpadlen;
  891: 		}
  892: 	}
  893: 
  894: 	/* Digits */
  895: 	while (place > 0) 
  896: 		dopr_outch (buffer, currlen, maxlen, convert[--place]);
  897:   
  898: 	/* Left Justified spaces */
  899: 	while (spadlen < 0) {
  900: 		dopr_outch (buffer, currlen, maxlen, ' ');
  901: 		++spadlen;
  902: 	}
  903: }
  904: 
  905: static LDOUBLE abs_val(LDOUBLE value)
  906: {
  907: 	LDOUBLE result = value;
  908: 
  909: 	if (value < 0)
  910: 		result = -value;
  911: 	
  912: 	return result;
  913: }
  914: 
  915: static LDOUBLE POW10(int exp)
  916: {
  917: 	LDOUBLE result = 1;
  918: 	
  919: 	while (exp) {
  920: 		result *= 10;
  921: 		exp--;
  922: 	}
  923:   
  924: 	return result;
  925: }
  926: 
  927: static LLONG ROUND(LDOUBLE value)
  928: {
  929: 	LLONG intpart;
  930: 
  931: 	intpart = (LLONG)value;
  932: 	value = value - intpart;
  933: 	if (value >= 0.5) intpart++;
  934: 	
  935: 	return intpart;
  936: }
  937: 
  938: /* a replacement for modf that doesn't need the math library. Should
  939:    be portable, but slow */
  940: static double my_modf(double x0, double *iptr)
  941: {
  942: 	int i;
  943: 	LLONG l=0;
  944: 	double x = x0;
  945: 	double f = 1.0;
  946: 
  947: 	for (i=0;i<100;i++) {
  948: 		l = (long)x;
  949: 		if (l <= (x+1) && l >= (x-1)) break;
  950: 		x *= 0.1;
  951: 		f *= 10.0;
  952: 	}
  953: 
  954: 	if (i == 100) {
  955: 		/* yikes! the number is beyond what we can handle. What do we do? */
  956: 		(*iptr) = 0;
  957: 		return 0;
  958: 	}
  959: 
  960: 	if (i != 0) {
  961: 		double i2;
  962: 		double ret;
  963: 
  964: 		ret = my_modf(x0-l*f, &i2);
  965: 		(*iptr) = l*f + i2;
  966: 		return ret;
  967: 	} 
  968: 
  969: 	(*iptr) = l;
  970: 	return x - (*iptr);
  971: }
  972: 
  973: 
  974: static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
  975: 		   LDOUBLE fvalue, int min, int max, int flags)
  976: {
  977: 	int signvalue = 0;
  978: 	double ufvalue;
  979: 	char iconvert[311];
  980: 	char fconvert[311];
  981: 	int iplace = 0;
  982: 	int fplace = 0;
  983: 	int padlen = 0; /* amount to pad */
  984: 	int zpadlen = 0; 
  985: 	int caps = 0;
  986: 	int idx;
  987: 	double intpart;
  988: 	double fracpart;
  989: 	double temp;
  990:   
  991: 	/* 
  992: 	 * AIX manpage says the default is 0, but Solaris says the default
  993: 	 * is 6, and sprintf on AIX defaults to 6
  994: 	 */
  995: 	if (max < 0)
  996: 		max = 6;
  997: 
  998: 	ufvalue = abs_val (fvalue);
  999: 
 1000: 	if (fvalue < 0) {
 1001: 		signvalue = '-';
 1002: 	} else {
 1003: 		if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
 1004: 			signvalue = '+';
 1005: 		} else {
 1006: 			if (flags & DP_F_SPACE)
 1007: 				signvalue = ' ';
 1008: 		}
 1009: 	}
 1010: 
 1011: #if 0
 1012: 	if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
 1013: #endif
 1014: 
 1015: #if 0
 1016: 	 if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
 1017: #endif
 1018: 
 1019: 	/* 
 1020: 	 * Sorry, we only support 9 digits past the decimal because of our 
 1021: 	 * conversion method
 1022: 	 */
 1023: 	if (max > 9)
 1024: 		max = 9;
 1025: 
 1026: 	/* We "cheat" by converting the fractional part to integer by
 1027: 	 * multiplying by a factor of 10
 1028: 	 */
 1029: 
 1030: 	temp = ufvalue;
 1031: 	my_modf(temp, &intpart);
 1032: 
 1033: 	fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
 1034: 	
 1035: 	if (fracpart >= POW10(max)) {
 1036: 		intpart++;
 1037: 		fracpart -= POW10(max);
 1038: 	}
 1039: 
 1040: 
 1041: 	/* Convert integer part */
 1042: 	do {
 1043: 		temp = intpart*0.1;
 1044: 		my_modf(temp, &intpart);
 1045: 		idx = (int) ((temp -intpart +0.05)* 10.0);
 1046: 		/* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
 1047: 		/* printf ("%llf, %f, %x\n", temp, intpart, idx); */
 1048: 		iconvert[iplace++] =
 1049: 			(caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
 1050: 	} while (intpart && (iplace < 311));
 1051: 	if (iplace == 311) iplace--;
 1052: 	iconvert[iplace] = 0;
 1053: 
 1054: 	/* Convert fractional part */
 1055: 	if (fracpart)
 1056: 	{
 1057: 		do {
 1058: 			temp = fracpart*0.1;
 1059: 			my_modf(temp, &fracpart);
 1060: 			idx = (int) ((temp -fracpart +0.05)* 10.0);
 1061: 			/* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
 1062: 			/* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
 1063: 			fconvert[fplace++] =
 1064: 			(caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
 1065: 		} while(fracpart && (fplace < 311));
 1066: 		if (fplace == 311) fplace--;
 1067: 	}
 1068: 	fconvert[fplace] = 0;
 1069:   
 1070: 	/* -1 for decimal point, another -1 if we are printing a sign */
 1071: 	padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
 1072: 	zpadlen = max - fplace;
 1073: 	if (zpadlen < 0) zpadlen = 0;
 1074: 	if (padlen < 0) 
 1075: 		padlen = 0;
 1076: 	if (flags & DP_F_MINUS) 
 1077: 		padlen = -padlen; /* Left Justifty */
 1078: 	
 1079: 	if ((flags & DP_F_ZERO) && (padlen > 0)) {
 1080: 		if (signvalue) {
 1081: 			dopr_outch (buffer, currlen, maxlen, signvalue);
 1082: 			--padlen;
 1083: 			signvalue = 0;
 1084: 		}
 1085: 		while (padlen > 0) {
 1086: 			dopr_outch (buffer, currlen, maxlen, '0');
 1087: 			--padlen;
 1088: 		}
 1089: 	}
 1090: 	while (padlen > 0) {
 1091: 		dopr_outch (buffer, currlen, maxlen, ' ');
 1092: 		--padlen;
 1093: 	}
 1094: 	if (signvalue) 
 1095: 		dopr_outch (buffer, currlen, maxlen, signvalue);
 1096: 	
 1097: 	while (iplace > 0) 
 1098: 		dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
 1099: 
 1100: #ifdef DEBUG_SNPRINTF
 1101: 	printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
 1102: #endif
 1103: 
 1104: 	/*
 1105: 	 * Decimal point.  This should probably use locale to find the correct
 1106: 	 * char to print out.
 1107: 	 */
 1108: 	if (max > 0) {
 1109: 		dopr_outch (buffer, currlen, maxlen, '.');
 1110: 		
 1111: 		while (zpadlen > 0) {
 1112: 			dopr_outch (buffer, currlen, maxlen, '0');
 1113: 			--zpadlen;
 1114: 		}
 1115: 
 1116: 		while (fplace > 0) 
 1117: 			dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
 1118: 	}
 1119: 
 1120: 	while (padlen < 0) {
 1121: 		dopr_outch (buffer, currlen, maxlen, ' ');
 1122: 		++padlen;
 1123: 	}
 1124: }
 1125: 
 1126: static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
 1127: {
 1128: 	if (*currlen < maxlen) {
 1129: 		buffer[(*currlen)] = c;
 1130: 	}
 1131: 	(*currlen)++;
 1132: }
 1133: 
 1134: static struct pr_chunk *new_chunk(void) {
 1135: 	struct pr_chunk *new_c = (struct pr_chunk *)malloc(sizeof(struct pr_chunk));
 1136: 
 1137: 	if (!new_c)
 1138: 		return NULL;
 1139: 
 1140: 	new_c->type = 0;
 1141: 	new_c->num = 0;
 1142: 	new_c->min = 0;
 1143: 	new_c->min_star = NULL;
 1144: 	new_c->max = -1;
 1145: 	new_c->max_star = NULL;
 1146: 	new_c->flags = 0;
 1147: 	new_c->cflags = 0;
 1148: 	new_c->start = 0;
 1149: 	new_c->len = 0;
 1150: 	new_c->value = 0;
 1151: 	new_c->fvalue = 0;
 1152: 	new_c->strvalue = NULL;
 1153: 	new_c->pnum = NULL;
 1154: 	new_c->next = NULL;
 1155: 
 1156: 	return new_c;
 1157: }
 1158: 
 1159: static int add_cnk_list_entry(struct pr_chunk_x **list,
 1160: 				int max_num, struct pr_chunk *chunk) {
 1161: 	struct pr_chunk_x *l;
 1162: 	struct pr_chunk **c;
 1163: 	int max;
 1164: 	int cnum;
 1165: 	int i, pos;
 1166: 
 1167: 	if (chunk->num > max_num) {
 1168: 		max = chunk->num;
 1169: 	
 1170: 		if (*list == NULL) {
 1171: 			l = (struct pr_chunk_x *)malloc(sizeof(struct pr_chunk_x) * max);
 1172: 			pos = 0;
 1173: 		} else {
 1174: 			l = (struct pr_chunk_x *)realloc(*list, sizeof(struct pr_chunk_x) * max);
 1175: 			pos = max_num;
 1176: 		}
 1177: 		if (l == NULL) {
 1178: 			for (i = 0; i < max; i++) {
 1179: 				if ((*list)[i].chunks) free((*list)[i].chunks);
 1180: 			}
 1181: 			return 0;
 1182: 		}
 1183: 		for (i = pos; i < max; i++) {
 1184: 			l[i].chunks = NULL;
 1185: 			l[i].num = 0;
 1186: 		}
 1187: 	} else {
 1188: 		l = *list;
 1189: 		max = max_num;
 1190: 	}
 1191: 
 1192: 	i = chunk->num - 1;
 1193: 	cnum = l[i].num + 1;
 1194: 	if (l[i].chunks == NULL) {
 1195: 		c = (struct pr_chunk **)malloc(sizeof(struct pr_chunk *) * cnum); 
 1196: 	} else {
 1197: 		c = (struct pr_chunk **)realloc(l[i].chunks, sizeof(struct pr_chunk *) * cnum);
 1198: 	}
 1199: 	if (c == NULL) {
 1200: 		for (i = 0; i < max; i++) {
 1201: 			if (l[i].chunks) free(l[i].chunks);
 1202: 		}
 1203: 		return 0;
 1204: 	}
 1205: 	c[l[i].num] = chunk;
 1206: 	l[i].chunks = c;
 1207: 	l[i].num = cnum;
 1208: 
 1209: 	*list = l;
 1210: 	return max;
 1211: }
 1212: 
 1213:  int rsync_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
 1214: {
 1215: 	return dopr(str, count, fmt, args);
 1216: }
 1217: #define vsnprintf rsync_vsnprintf
 1218: #endif
 1219: 
 1220: /* yes this really must be a ||. Don't muck with this (tridge)
 1221:  *
 1222:  * The logic for these two is that we need our own definition if the
 1223:  * OS *either* has no definition of *sprintf, or if it does have one
 1224:  * that doesn't work properly according to the autoconf test.
 1225:  */
 1226: #if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
 1227: int rsync_snprintf(char *str,size_t count,const char *fmt,...)
 1228: {
 1229: 	size_t ret;
 1230: 	va_list ap;
 1231:     
 1232: 	va_start(ap, fmt);
 1233: 	ret = vsnprintf(str, count, fmt, ap);
 1234: 	va_end(ap);
 1235: 	return ret;
 1236: }
 1237: #define snprintf rsync_snprintf
 1238: #endif
 1239: 
 1240: #ifndef HAVE_VASPRINTF
 1241:  int vasprintf(char **ptr, const char *format, va_list ap)
 1242: {
 1243: 	int ret;
 1244: 	va_list ap2;
 1245: 
 1246: 	VA_COPY(ap2, ap);
 1247: 	ret = vsnprintf(NULL, 0, format, ap2);
 1248: 	va_end(ap2);
 1249: 	if (ret < 0) return ret;
 1250: 
 1251: 	(*ptr) = (char *)malloc(ret+1);
 1252: 	if (!*ptr) return -1;
 1253: 
 1254: 	VA_COPY(ap2, ap);
 1255: 	ret = vsnprintf(*ptr, ret+1, format, ap2);
 1256: 	va_end(ap2);
 1257: 
 1258: 	return ret;
 1259: }
 1260: #endif
 1261: 
 1262: 
 1263: #ifndef HAVE_ASPRINTF
 1264:  int asprintf(char **ptr, const char *format, ...)
 1265: {
 1266: 	va_list ap;
 1267: 	int ret;
 1268: 	
 1269: 	*ptr = NULL;
 1270: 	va_start(ap, format);
 1271: 	ret = vasprintf(ptr, format, ap);
 1272: 	va_end(ap);
 1273: 
 1274: 	return ret;
 1275: }
 1276: #endif
 1277: 
 1278: #ifdef TEST_SNPRINTF
 1279: 
 1280:  int sprintf(char *str,const char *fmt,...);
 1281:  int printf(const char *fmt,...);
 1282: 
 1283:  int main (void)
 1284: {
 1285: 	char buf1[1024];
 1286: 	char buf2[1024];
 1287: 	char *buf3;
 1288: 	char *fp_fmt[] = {
 1289: 		"%1.1f",
 1290: 		"%-1.5f",
 1291: 		"%1.5f",
 1292: 		"%123.9f",
 1293: 		"%10.5f",
 1294: 		"% 10.5f",
 1295: 		"%+22.9f",
 1296: 		"%+4.9f",
 1297: 		"%01.3f",
 1298: 		"%4f",
 1299: 		"%3.1f",
 1300: 		"%3.2f",
 1301: 		"%.0f",
 1302: 		"%f",
 1303: 		"%-8.8f",
 1304: 		"%-9.9f",
 1305: 		NULL
 1306: 	};
 1307: 	double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996, 
 1308: 			     0.9996, 1.996, 4.136, 5.030201, 0.00205,
 1309: 			     /* END LIST */ 0};
 1310: 	char *int_fmt[] = {
 1311: 		"%-1.5d",
 1312: 		"%1.5d",
 1313: 		"%123.9d",
 1314: 		"%5.5d",
 1315: 		"%10.5d",
 1316: 		"% 10.5d",
 1317: 		"%+22.33d",
 1318: 		"%01.3d",
 1319: 		"%4d",
 1320: 		"%d",
 1321: 		NULL
 1322: 	};
 1323: 	long int_nums[] = { -1, 134, 91340, 341, 0203, 1234567890, 0};
 1324: 	char *str_fmt[] = {
 1325: 		"%10.5s",
 1326: 		"%-10.5s",
 1327: 		"%5.10s",
 1328: 		"%-5.10s",
 1329: 		"%10.1s",
 1330: 		"%0.10s",
 1331: 		"%10.0s",
 1332: 		"%1.10s",
 1333: 		"%s",
 1334: 		"%.1s",
 1335: 		"%.10s",
 1336: 		"%10s",
 1337: 		NULL
 1338: 	};
 1339: 	char *str_vals[] = {"hello", "a", "", "a longer string", NULL};
 1340: #ifdef HAVE_LONG_LONG
 1341: 	char *ll_fmt[] = {
 1342: 		"%llu",
 1343: 		NULL
 1344: 	};
 1345: 	LLONG ll_nums[] = { 134, 91340, 341, 0203, 1234567890, 128006186140000000LL, 0};
 1346: #endif
 1347: 	int x, y;
 1348: 	int fail = 0;
 1349: 	int num = 0;
 1350: 	int l1, l2;
 1351: 	char *ss_fmt[] = {
 1352: 		"%zd",
 1353: 		"%zu",
 1354: 		NULL
 1355: 	};
 1356: 	size_t ss_nums[] = {134, 91340, 123456789, 0203, 1234567890, 0};
 1357: 
 1358: 	printf ("Testing snprintf format codes against system sprintf...\n");
 1359: 
 1360: 	for (x = 0; fp_fmt[x] ; x++) {
 1361: 		for (y = 0; fp_nums[y] != 0 ; y++) {
 1362: 			buf1[0] = buf2[0] = '\0';
 1363: 			l1 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
 1364: 			l2 = sprintf (buf2, fp_fmt[x], fp_nums[y]);
 1365: 			buf1[1023] = buf2[1023] = '\0';
 1366: 			if (strcmp (buf1, buf2) || (l1 != l2)) {
 1367: 				printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
 1368: 				       fp_fmt[x], l1, buf1, l2, buf2);
 1369: 				fail++;
 1370: 			}
 1371: 			num++;
 1372: 		}
 1373: 	}
 1374: 
 1375: 	for (x = 0; int_fmt[x] ; x++) {
 1376: 		for (y = 0; int_nums[y] != 0 ; y++) {
 1377: 			buf1[0] = buf2[0] = '\0';
 1378: 			l1 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
 1379: 			l2 = sprintf (buf2, int_fmt[x], int_nums[y]);
 1380: 			buf1[1023] = buf2[1023] = '\0';
 1381: 			if (strcmp (buf1, buf2) || (l1 != l2)) {
 1382: 				printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
 1383: 				       int_fmt[x], l1, buf1, l2, buf2);
 1384: 				fail++;
 1385: 			}
 1386: 			num++;
 1387: 		}
 1388: 	}
 1389: 
 1390: 	for (x = 0; str_fmt[x] ; x++) {
 1391: 		for (y = 0; str_vals[y] != 0 ; y++) {
 1392: 			buf1[0] = buf2[0] = '\0';
 1393: 			l1 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
 1394: 			l2 = sprintf (buf2, str_fmt[x], str_vals[y]);
 1395: 			buf1[1023] = buf2[1023] = '\0';
 1396: 			if (strcmp (buf1, buf2) || (l1 != l2)) {
 1397: 				printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
 1398: 				       str_fmt[x], l1, buf1, l2, buf2);
 1399: 				fail++;
 1400: 			}
 1401: 			num++;
 1402: 		}
 1403: 	}
 1404: 
 1405: #ifdef HAVE_LONG_LONG
 1406: 	for (x = 0; ll_fmt[x] ; x++) {
 1407: 		for (y = 0; ll_nums[y] != 0 ; y++) {
 1408: 			buf1[0] = buf2[0] = '\0';
 1409: 			l1 = snprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]);
 1410: 			l2 = sprintf (buf2, ll_fmt[x], ll_nums[y]);
 1411: 			buf1[1023] = buf2[1023] = '\0';
 1412: 			if (strcmp (buf1, buf2) || (l1 != l2)) {
 1413: 				printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
 1414: 				       ll_fmt[x], l1, buf1, l2, buf2);
 1415: 				fail++;
 1416: 			}
 1417: 			num++;
 1418: 		}
 1419: 	}
 1420: #endif
 1421: 
 1422: #define BUFSZ 2048
 1423: 
 1424: 	buf1[0] = buf2[0] = '\0';
 1425: 	if ((buf3 = malloc(BUFSZ)) == NULL) {
 1426: 		fail++;
 1427: 	} else {
 1428: 		num++;
 1429: 		memset(buf3, 'a', BUFSZ);
 1430: 		snprintf(buf1, sizeof(buf1), "%.*s", 1, buf3);
 1431: 		buf1[1023] = '\0';
 1432: 		if (strcmp(buf1, "a") != 0) {
 1433: 			printf("length limit buf1 '%s' expected 'a'\n", buf1);
 1434: 			fail++;
 1435: 		}
 1436:         }
 1437: 
 1438: 	buf1[0] = buf2[0] = '\0';
 1439: 	l1 = snprintf(buf1, sizeof(buf1), "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9);
 1440: 	l2 = sprintf(buf2, "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9);
 1441: 	buf1[1023] = buf2[1023] = '\0';
 1442: 	if (strcmp(buf1, buf2) || (l1 != l2)) {
 1443: 		printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
 1444: 				"%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2);
 1445: 		fail++;
 1446: 	}
 1447: 
 1448: 	buf1[0] = buf2[0] = '\0';
 1449: 	l1 = snprintf(buf1, sizeof(buf1), "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9);
 1450: 	l2 = sprintf(buf2, "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9);
 1451: 	buf1[1023] = buf2[1023] = '\0';
 1452: 	if (strcmp(buf1, buf2)) {
 1453: 		printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
 1454: 				"%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2);
 1455: 		fail++;
 1456: 	}
 1457: 
 1458: 	for (x = 0; ss_fmt[x] ; x++) {
 1459: 		for (y = 0; ss_nums[y] != 0 ; y++) {
 1460: 			buf1[0] = buf2[0] = '\0';
 1461: 			l1 = snprintf(buf1, sizeof(buf1), ss_fmt[x], ss_nums[y]);
 1462: 			l2 = sprintf (buf2, ss_fmt[x], ss_nums[y]);
 1463: 			buf1[1023] = buf2[1023] = '\0';
 1464: 			if (strcmp (buf1, buf2) || (l1 != l2)) {
 1465: 				printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
 1466: 				       ss_fmt[x], l1, buf1, l2, buf2);
 1467: 				fail++;
 1468: 			}
 1469: 			num++;
 1470: 		}
 1471: 	}
 1472: #if 0
 1473: 	buf1[0] = buf2[0] = '\0';
 1474: 	l1 = snprintf(buf1, sizeof(buf1), "%lld", (LLONG)1234567890);
 1475: 	l2 = sprintf(buf2, "%lld", (LLONG)1234567890);
 1476: 	buf1[1023] = buf2[1023] = '\0';
 1477: 	if (strcmp(buf1, buf2)) {
 1478: 		printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
 1479: 				"%lld", l1, buf1, l2, buf2);
 1480: 		fail++;
 1481: 	}
 1482: 
 1483: 	buf1[0] = buf2[0] = '\0';
 1484: 	l1 = snprintf(buf1, sizeof(buf1), "%Lf", (LDOUBLE)890.1234567890123);
 1485: 	l2 = sprintf(buf2, "%Lf", (LDOUBLE)890.1234567890123);
 1486: 	buf1[1023] = buf2[1023] = '\0';
 1487: 	if (strcmp(buf1, buf2)) {
 1488: 		printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
 1489: 				"%Lf", l1, buf1, l2, buf2);
 1490: 		fail++;
 1491: 	}
 1492: #endif
 1493: 	printf ("%d tests failed out of %d.\n", fail, num);
 1494: 
 1495: 	printf("seeing how many digits we support\n");
 1496: 	{
 1497: 		double v0 = 0.12345678901234567890123456789012345678901;
 1498: 		for (x=0; x<100; x++) {
 1499: 			double p = pow(10, x); 
 1500: 			double r = v0*p;
 1501: 			snprintf(buf1, sizeof(buf1), "%1.1f", r);
 1502: 			sprintf(buf2,                "%1.1f", r);
 1503: 			if (strcmp(buf1, buf2)) {
 1504: 				printf("we seem to support %d digits\n", x-1);
 1505: 				break;
 1506: 			}
 1507: 		}
 1508: 	}
 1509: 
 1510: 	return 0;
 1511: }
 1512: #endif /* TEST_SNPRINTF */

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