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

📄 snprintf.c

📁 samba服务器!
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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. * * Darren Tucker (dtucker@zip.com.au) 2005 *    Fix bug allowing read overruns of the source string with "%.*s" *    Usually harmless unless the read runs outside the process' allocation *    (eg if your malloc does guard pages) in which case it will segfault. *    From OpenSSH.  Also added test for same. * * Simo Sorce (idra@samba.org) Jan 2006 *  *    Add support for position independent parameters  *    fix fmtstr now it conforms to sprintf wrt min.max * **************************************************************/#include "replace.h"#include "system/locale.h"#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 */#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 *//* yes this really must be a ||. Don't muck with this (tridge) */#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)#ifdef HAVE_LONG_DOUBLE#define LDOUBLE long double#else#define LDOUBLE double#endif#ifdef HAVE_LONG_LONG#define LLONG long long#else#define LLONG long#endif#ifndef VA_COPY#ifdef HAVE_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_CHAR    1#define DP_C_SHORT   2#define DP_C_LONG    3#define DP_C_LDOUBLE 4#define DP_C_LLONG   5#define DP_C_SIZET   6/* Chunk types */#define CNK_FMT_STR 0#define CNK_INT     1#define CNK_OCTAL   2#define CNK_UINT    3#define CNK_HEX     4#define CNK_FLOAT   5#define CNK_CHAR    6#define CNK_STRING  7#define CNK_PTR     8#define CNK_NUM     9#define CNK_PRCNT   10#define char_to_int(p) ((p)- '0')#ifndef MAX#define MAX(p,q) (((p) >= (q)) ? (p) : (q))#endifstruct pr_chunk {	int type; /* chunk type */	int num; /* parameter number */	int min; 	int max;	int flags;	int cflags;	int start;	int len;	LLONG value;	LDOUBLE fvalue;	char *strvalue;	void *pnum;	struct pr_chunk *min_star;	struct pr_chunk *max_star;	struct pr_chunk *next;};struct pr_chunk_x {	struct pr_chunk **chunks;	int num;};static int 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,		    LLONG 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 struct pr_chunk *new_chunk(void);static int add_cnk_list_entry(struct pr_chunk_x **list,				int max_num, struct pr_chunk *chunk);static int dopr(char *buffer, size_t maxlen, const char *format, va_list args_in){	char ch;	int state;	int pflag;	int pnum;	int pfirst;	size_t currlen;	va_list args;	const char *base;	struct pr_chunk *chunks = NULL;	struct pr_chunk *cnk = NULL;	struct pr_chunk_x *clist = NULL;	int max_pos;	int ret = -1;	VA_COPY(args, args_in);	state = DP_S_DEFAULT;	pfirst = 1;	pflag = 0;	pnum = 0;	max_pos = 0;	base = format;	ch = *format++;		/* retrieve the string structure as chunks */	while (state != DP_S_DONE) {		if (ch == '\0') 			state = DP_S_DONE;		switch(state) {		case DP_S_DEFAULT:						if (cnk) {				cnk->next = new_chunk();				cnk = cnk->next;			} else {				cnk = new_chunk();			}			if (!cnk) goto done;			if (!chunks) chunks = cnk;						if (ch == '%') {				state = DP_S_FLAGS;				ch = *format++;			} else {				cnk->type = CNK_FMT_STR;				cnk->start = format - base -1;				while ((ch != '\0') && (ch != '%')) ch = *format++;				cnk->len = format - base - cnk->start -1;			}			break;		case DP_S_FLAGS:			switch (ch) {			case '-':				cnk->flags |= DP_F_MINUS;				ch = *format++;				break;			case '+':				cnk->flags |= DP_F_PLUS;				ch = *format++;				break;			case ' ':				cnk->flags |= DP_F_SPACE;				ch = *format++;				break;			case '#':				cnk->flags |= DP_F_NUM;				ch = *format++;				break;			case '0':				cnk->flags |= DP_F_ZERO;				ch = *format++;				break;			case 'I':				/* internationalization not supported yet */				ch = *format++;				break;			default:				state = DP_S_MIN;				break;			}			break;		case DP_S_MIN:			if (isdigit((unsigned char)ch)) {				cnk->min = 10 * cnk->min + char_to_int (ch);				ch = *format++;			} else if (ch == '$') {				if (!pfirst && !pflag) {					/* parameters must be all positioned or none */					goto done;				}				if (pfirst) {					pfirst = 0;					pflag = 1;				}				if (cnk->min == 0) /* what ?? */					goto done;				cnk->num = cnk->min;				cnk->min = 0;				ch = *format++;			} else if (ch == '*') {				if (pfirst) pfirst = 0;				cnk->min_star = new_chunk();				if (!cnk->min_star) /* out of memory :-( */					goto done;				cnk->min_star->type = CNK_INT;				if (pflag) {					int num;					ch = *format++;					if (!isdigit((unsigned char)ch)) {						/* parameters must be all positioned or none */						goto done;					}					for (num = 0; isdigit((unsigned char)ch); ch = *format++) {						num = 10 * num + char_to_int(ch);					}					cnk->min_star->num = num;					if (ch != '$') /* what ?? */						goto done;				} else {					cnk->min_star->num = ++pnum;				}				max_pos = add_cnk_list_entry(&clist, max_pos, cnk->min_star);				if (max_pos == 0) /* out of memory :-( */					goto done;				ch = *format++;				state = DP_S_DOT;			} else {				if (pfirst) pfirst = 0;				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 (cnk->max < 0)					cnk->max = 0;				cnk->max = 10 * cnk->max + char_to_int (ch);				ch = *format++;			} else if (ch == '$') {				if (!pfirst && !pflag) {					/* parameters must be all positioned or none */					goto done;				}				if (cnk->max <= 0) /* what ?? */					goto done;				cnk->num = cnk->max;				cnk->max = -1;				ch = *format++;			} else if (ch == '*') {				cnk->max_star = new_chunk();				if (!cnk->max_star) /* out of memory :-( */					goto done;				cnk->max_star->type = CNK_INT;				if (pflag) {					int num;					ch = *format++;					if (!isdigit((unsigned char)ch)) {						/* parameters must be all positioned or none */						goto done;					}					for (num = 0; isdigit((unsigned char)ch); ch = *format++) {						num = 10 * num + char_to_int(ch);					}					cnk->max_star->num = num;					if (ch != '$') /* what ?? */						goto done;				} else {					cnk->max_star->num = ++pnum;				}				max_pos = add_cnk_list_entry(&clist, max_pos, cnk->max_star);				if (max_pos == 0) /* out of memory :-( */					goto done;				ch = *format++;				state = DP_S_MOD;			} else {				state = DP_S_MOD;			}			break;		case DP_S_MOD:			switch (ch) {			case 'h':				cnk->cflags = DP_C_SHORT;				ch = *format++;				if (ch == 'h') {					cnk->cflags = DP_C_CHAR;					ch = *format++;				}				break;			case 'l':				cnk->cflags = DP_C_LONG;				ch = *format++;				if (ch == 'l') {	/* It's a long long */					cnk->cflags = DP_C_LLONG;					ch = *format++;				}				break;			case 'L':				cnk->cflags = DP_C_LDOUBLE;				ch = *format++;				break;			case 'z':				cnk->cflags = DP_C_SIZET;				ch = *format++;				break;			default:				break;			}			state = DP_S_CONV;			break;		case DP_S_CONV:			if (cnk->num == 0) cnk->num = ++pnum;			max_pos = add_cnk_list_entry(&clist, max_pos, cnk);			if (max_pos == 0) /* out of memory :-( */				goto done;						switch (ch) {			case 'd':			case 'i':				cnk->type = CNK_INT;				break;			case 'o':				cnk->type = CNK_OCTAL;				cnk->flags |= DP_F_UNSIGNED;				break;			case 'u':				cnk->type = CNK_UINT;				cnk->flags |= DP_F_UNSIGNED;				break;			case 'X':				cnk->flags |= DP_F_UP;			case 'x':				cnk->type = CNK_HEX;				cnk->flags |= DP_F_UNSIGNED;				break;			case 'A':				/* hex float not supported yet */			case 'E':			case 'G':			case 'F':				cnk->flags |= DP_F_UP;			case 'a':				/* hex float not supported yet */			case 'e':			case 'f':			case 'g':				cnk->type = CNK_FLOAT;				break;			case 'c':				cnk->type = CNK_CHAR;				break;			case 's':				cnk->type = CNK_STRING;				break;			case 'p':				cnk->type = CNK_PTR;				break;			case 'n':				cnk->type = CNK_NUM;				break;			case '%':

⌨️ 快捷键说明

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