⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 snprintf.c

📁 Rsync 3.0.5 source code
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * NOTE: If you change this file, please merge it into rsync, samba, etc. *//* * Copyright Patrick Powell 1995 * This code is based on code written by Patrick Powell (papowell@astart.com) * It may be used for any purpose as long as this notice remains intact * on all source code distributions *//************************************************************** * Original: * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 * A bombproof version of doprnt (dopr) included. * Sigh.  This sort of thing is always nasty do deal with.  Note that * the version here does not include floating point... * * snprintf() is used instead of sprintf() as it does limit checks * for string length.  This covers a nasty loophole. * * The other functions are there to prevent NULL pointers from * causing nast effects. * * More Recently: *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43 *  This was ugly.  It is still ugly.  I opted out of floating point *  numbers, but the formatter understands just about everything *  from the normal C string format, at least as far as I can tell from *  the Solaris 2.5 printf(3S) man page. * *  Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1 *    Ok, added some minimal floating point support, which means this *    probably requires libm on most operating systems.  Don't yet *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint() *    was pretty badly broken, it just wasn't being exercised in ways *    which showed it, so that's been fixed.  Also, formated the code *    to mutt conventions, and removed dead code left over from the *    original.  Also, there is now a builtin-test, just compile with: *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm *    and run snprintf for results. *  *  Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i *    The PGP code was using unsigned hexadecimal formats.  *    Unfortunately, unsigned formats simply didn't work. * *  Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8 *    The original code assumed that both snprintf() and vsnprintf() were *    missing.  Some systems only have snprintf() but not vsnprintf(), so *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. * *  Andrew Tridgell (tridge@samba.org) Oct 1998 *    fixed handling of %.0f *    added test for HAVE_LONG_DOUBLE * * tridge@samba.org, idra@samba.org, April 2001 *    got rid of fcvt code (twas buggy and made testing harder) *    added C99 semantics * * date: 2002/12/19 19:56:31;  author: herb;  state: Exp;  lines: +2 -0 * actually print args for %g and %e *  * date: 2002/06/03 13:37:52;  author: jmcd;  state: Exp;  lines: +8 -0 * Since includes.h isn't included here, VA_COPY has to be defined here.  I don't * see any include file that is guaranteed to be here, so I'm defining it * locally.  Fixes AIX and Solaris builds. *  * date: 2002/06/03 03:07:24;  author: tridge;  state: Exp;  lines: +5 -13 * put the ifdef for HAVE_VA_COPY in one place rather than in lots of * functions *  * date: 2002/05/17 14:51:22;  author: jmcd;  state: Exp;  lines: +21 -4 * Fix usage of va_list passed as an arg.  Use __va_copy before using it * when it exists. *  * date: 2002/04/16 22:38:04;  author: idra;  state: Exp;  lines: +20 -14 * Fix incorrect zpadlen handling in fmtfp. * Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it. * few mods to make it easier to compile the tests. * addedd the "Ollie" test to the floating point ones. * * Martin Pool (mbp@samba.org) April 2003 *    Remove NO_CONFIG_H so that the test case can be built within a source *    tree with less trouble. *    Remove unnecessary SAFE_FREE() definition. * * Martin Pool (mbp@samba.org) May 2003 *    Put in a prototype for dummy_snprintf() to quiet compiler warnings. * *    Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even *    if the C library has some snprintf functions already. **************************************************************/#ifndef NO_CONFIG_H#include "config.h"#else#define NULL 0#endif #ifdef TEST_SNPRINTF /* need math library headers for testing *//* In test mode, we pretend that this system doesn't have any snprintf * functions, regardless of what config.h says. */#  undef HAVE_SNPRINTF#  undef HAVE_VSNPRINTF#  undef HAVE_C99_VSNPRINTF#  undef HAVE_ASPRINTF#  undef HAVE_VASPRINTF#  include <math.h>#endif /* TEST_SNPRINTF */#ifdef HAVE_STRING_H#include <string.h>#endif#ifdef HAVE_STRINGS_H#include <strings.h>#endif#ifdef HAVE_CTYPE_H#include <ctype.h>#endif#include <sys/types.h>#include <stdarg.h>#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)/* only include stdio.h if we are not re-defining snprintf or vsnprintf */#include <stdio.h> /* make the compiler happy with an empty file */ void dummy_snprintf(void); void dummy_snprintf(void) {} #endif /* HAVE_SNPRINTF, etc */#ifdef HAVE_LONG_DOUBLE#define LDOUBLE long double#else#define LDOUBLE double#endif#if SIZEOF_LONG_LONG#define LLONG long long#else#define LLONG long#endif#ifndef VA_COPY#if defined HAVE_VA_COPY || defined va_copy#define VA_COPY(dest, src) va_copy(dest, src)#else#ifdef HAVE___VA_COPY#define VA_COPY(dest, src) __va_copy(dest, src)#else#define VA_COPY(dest, src) (dest) = (src)#endif#endif/* * dopr(): poor man's version of doprintf *//* format read states */#define DP_S_DEFAULT 0#define DP_S_FLAGS   1#define DP_S_MIN     2#define DP_S_DOT     3#define DP_S_MAX     4#define DP_S_MOD     5#define DP_S_CONV    6#define DP_S_DONE    7/* format flags - Bits */#define DP_F_MINUS 	(1 << 0)#define DP_F_PLUS  	(1 << 1)#define DP_F_SPACE 	(1 << 2)#define DP_F_NUM   	(1 << 3)#define DP_F_ZERO  	(1 << 4)#define DP_F_UP    	(1 << 5)#define DP_F_UNSIGNED 	(1 << 6)/* Conversion Flags */#define DP_C_SHORT   1#define DP_C_LONG    2#define DP_C_LDOUBLE 3#define DP_C_LLONG   4#define char_to_int(p) ((p)- '0')#ifndef MAX#define MAX(p,q) (((p) >= (q)) ? (p) : (q))#endif/* yes this really must be a ||. Don't muck with this (tridge) */#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)static size_t dopr(char *buffer, size_t maxlen, const char *format, 		   va_list args_in);static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,		    char *value, int flags, int min, int max);static void fmtint(char *buffer, size_t *currlen, size_t maxlen,		    long value, int base, int min, int max, int flags);static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,		   LDOUBLE fvalue, int min, int max, int flags);static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in){	char ch;	LLONG value;	LDOUBLE fvalue;	char *strvalue;	int min;	int max;	int state;	int flags;	int cflags;	size_t currlen;	va_list args;	VA_COPY(args, args_in);		state = DP_S_DEFAULT;	currlen = flags = cflags = min = 0;	max = -1;	ch = *format++;		while (state != DP_S_DONE) {		if (ch == '\0') 			state = DP_S_DONE;		switch(state) {		case DP_S_DEFAULT:			if (ch == '%') 				state = DP_S_FLAGS;			else 				dopr_outch (buffer, &currlen, maxlen, ch);			ch = *format++;			break;		case DP_S_FLAGS:			switch (ch) {			case '-':				flags |= DP_F_MINUS;				ch = *format++;				break;			case '+':				flags |= DP_F_PLUS;				ch = *format++;				break;			case ' ':				flags |= DP_F_SPACE;				ch = *format++;				break;			case '#':				flags |= DP_F_NUM;				ch = *format++;				break;			case '0':				flags |= DP_F_ZERO;				ch = *format++;				break;			default:				state = DP_S_MIN;				break;			}			break;		case DP_S_MIN:			if (isdigit((unsigned char)ch)) {				min = 10*min + char_to_int (ch);				ch = *format++;			} else if (ch == '*') {				min = va_arg (args, int);				ch = *format++;				state = DP_S_DOT;			} else {				state = DP_S_DOT;			}			break;		case DP_S_DOT:			if (ch == '.') {				state = DP_S_MAX;				ch = *format++;			} else { 				state = DP_S_MOD;			}			break;		case DP_S_MAX:			if (isdigit((unsigned char)ch)) {				if (max < 0)					max = 0;				max = 10*max + char_to_int (ch);				ch = *format++;			} else if (ch == '*') {				max = va_arg (args, int);				ch = *format++;				state = DP_S_MOD;			} else {				state = DP_S_MOD;			}			break;		case DP_S_MOD:			switch (ch) {			case 'h':				cflags = DP_C_SHORT;				ch = *format++;				break;			case 'l':				cflags = DP_C_LONG;				ch = *format++;				if (ch == 'l') {	/* It's a long long */					cflags = DP_C_LLONG;					ch = *format++;				}				break;			case 'L':				cflags = DP_C_LDOUBLE;				ch = *format++;				break;			default:				break;			}			state = DP_S_CONV;			break;		case DP_S_CONV:			switch (ch) {			case 'd':			case 'i':				if (cflags == DP_C_SHORT) 					value = va_arg (args, int);				else if (cflags == DP_C_LONG)					value = va_arg (args, long int);				else if (cflags == DP_C_LLONG)					value = va_arg (args, LLONG);				else					value = va_arg (args, int);				fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);				break;			case 'o':				flags |= DP_F_UNSIGNED;				if (cflags == DP_C_SHORT)					value = va_arg (args, unsigned int);				else if (cflags == DP_C_LONG)					value = (long)va_arg (args, unsigned long int);				else if (cflags == DP_C_LLONG)					value = (long)va_arg (args, unsigned LLONG);				else					value = (long)va_arg (args, unsigned int);				fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);				break;			case 'u':				flags |= DP_F_UNSIGNED;				if (cflags == DP_C_SHORT)					value = va_arg (args, unsigned int);				else if (cflags == DP_C_LONG)					value = (long)va_arg (args, unsigned long int);				else if (cflags == DP_C_LLONG)					value = (LLONG)va_arg (args, unsigned LLONG);				else					value = (long)va_arg (args, unsigned int);				fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);				break;			case 'X':				flags |= DP_F_UP;			case 'x':				flags |= DP_F_UNSIGNED;				if (cflags == DP_C_SHORT)					value = va_arg (args, unsigned int);				else if (cflags == DP_C_LONG)					value = (long)va_arg (args, unsigned long int);				else if (cflags == DP_C_LLONG)					value = (LLONG)va_arg (args, unsigned LLONG);				else					value = (long)va_arg (args, unsigned int);				fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);				break;			case 'f':				if (cflags == DP_C_LDOUBLE)					fvalue = va_arg (args, LDOUBLE);				else					fvalue = va_arg (args, double);				/* um, floating point? */				fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);				break;			case 'E':				flags |= DP_F_UP;			case 'e':				if (cflags == DP_C_LDOUBLE)					fvalue = va_arg (args, LDOUBLE);				else					fvalue = va_arg (args, double);				fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);				break;			case 'G':				flags |= DP_F_UP;			case 'g':				if (cflags == DP_C_LDOUBLE)					fvalue = va_arg (args, LDOUBLE);				else					fvalue = va_arg (args, double);				fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);				break;			case 'c':				dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));				break;			case 's':				strvalue = va_arg (args, char *);				if (!strvalue) strvalue = "(NULL)";				if (max == -1) {					max = strlen(strvalue);				}				if (min > 0 && max >= 0 && min > max) max = min;				fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);				break;			case 'p':				strvalue = va_arg (args, void *);				fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);				break;			case 'n':				if (cflags == DP_C_SHORT) {					short int *num;					num = va_arg (args, short int *);					*num = currlen;				} else if (cflags == DP_C_LONG) {					long int *num;					num = va_arg (args, long int *);					*num = (long int)currlen;				} else if (cflags == DP_C_LLONG) {					LLONG *num;					num = va_arg (args, LLONG *);					*num = (LLONG)currlen;				} else {					int *num;					num = va_arg (args, int *);					*num = currlen;				}				break;			case '%':				dopr_outch (buffer, &currlen, maxlen, ch);				break;			case 'w':				/* not supported yet, treat as next char */				ch = *format++;				break;			default:				/* Unknown, skip */				break;			}			ch = *format++;			state = DP_S_DEFAULT;			flags = cflags = min = 0;			max = -1;			break;		case DP_S_DONE:			break;		default:			/* hmm? */			break; /* some picky compilers need this */		}	}	if (maxlen != 0) {		if (currlen < maxlen - 1) 			buffer[currlen] = '\0';		else if (maxlen > 0) 			buffer[maxlen - 1] = '\0';	}		return currlen;}static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,		    char *value, int flags, int min, int max){	int padlen, strln;     /* amount to pad */	int cnt = 0;#ifdef DEBUG_SNPRINTF	printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);#endif	if (value == 0) {		value = "<NULL>";	}	for (strln = 0; value[strln]; ++strln); /* strlen */	padlen = min - strln;	if (padlen < 0) 		padlen = 0;	if (flags & DP_F_MINUS) 		padlen = -padlen; /* Left Justify */		while ((padlen > 0) && (cnt < max)) {		dopr_outch (buffer, currlen, maxlen, ' ');		--padlen;		++cnt;	}	while (*value && (cnt < max)) {		dopr_outch (buffer, currlen, maxlen, *value++);		++cnt;	}	while ((padlen < 0) && (cnt < max)) {		dopr_outch (buffer, currlen, maxlen, ' ');		++padlen;		++cnt;	}}/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */static void fmtint(char *buffer, size_t *currlen, size_t maxlen,		    long value, int base, int min, int max, int flags){	int signvalue = 0;	unsigned long uvalue;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -