snprintf.c

来自「一个很有名的浏览器」· C语言 代码 · 共 1,031 行 · 第 1/2 页

C
1,031
字号
	if (flags & DP_F_ZERO) {		zpadlen = MAX(zpadlen, spadlen);		spadlen = 0;	}	if (flags & DP_F_MINUS)		spadlen = -spadlen; /* Left Justifty */#ifdef DEBUG_SNPRINTF	printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",	       zpadlen, spadlen, min, max, place);#endif	/* Spaces */	while (spadlen > 0) {		dopr_outch(buffer, currlen, maxlen, ' ');		--spadlen;	}	/* Sign */	if (signvalue)		dopr_outch(buffer, currlen, maxlen, signvalue);	/* Zeros */	while (zpadlen > 0) {		dopr_outch(buffer, currlen, maxlen, '0');		--zpadlen;	}	/* Digits */	while (place > 0)		dopr_outch(buffer, currlen, maxlen, convert[--place]);	/* Left Justified spaces */	while (spadlen < 0) {		dopr_outch(buffer, currlen, maxlen, ' ');		++spadlen;	}}static LDOUBLEmy_abs(LDOUBLE value){	LDOUBLE result = value;	if (value < 0)		result = -value;	return result;}static LDOUBLEmy_pow10(int exp){	LDOUBLE result = 1;	while (exp) {		result *= 10;		exp--;	}	return result;}static LLONGmy_round(LDOUBLE value){	LLONG intpart;	intpart = (LLONG) value;	value = value - intpart;	if (value >= 0.5) intpart++;	return intpart;}/* a replacement for modf that doesn't need the math library. Should   be portable, but slow */static doublemy_modf(double x0, double *iptr){	int i;	long l;	double x = x0;	double f = 1.0;	for (i = 0; i < 100; i++) {		l = (long) x;		if (l <= (x + 1) && l >= (x - 1)) break;		x *= 0.1;		f *= 10.0;	}	if (i == 100) {		/* yikes! the number is beyond what we can handle. What do we do? */		(*iptr) = 0;		return 0;	}	if (i != 0) {		double i2;		double ret;		ret = my_modf(x0 - l * f, &i2);		(*iptr) = l * f + i2;		return ret;	}	(*iptr) = l;	return x - (*iptr);}static voidfmtfp(char *buffer, size_t *currlen, size_t maxlen,      LDOUBLE fvalue, int min, int max, int flags){	int signvalue = 0;	double ufvalue;	char iconvert[311];	char fconvert[311];	char *numbers = (char *) &hexnumbers;	int iplace = 0;	int fplace = 0;	int padlen = 0; /* amount to pad */	int zpadlen = 0;	int index;	double intpart;	double fracpart;	double temp;	LDOUBLE pow;	/*	 * AIX manpage says the default is 0, but Solaris says the default	 * is 6, and sprintf on AIX defaults to 6	 */	if (max < 0)		max = 6;	ufvalue = my_abs(fvalue);	if (fvalue < 0) {		signvalue = '-';	} else {		if (flags & DP_F_PLUS) { /* Do a sign (+/i) */			signvalue = '+';		} else {			if (flags & DP_F_SPACE)				signvalue = ' ';		}	}#if 0	if (flags & DP_F_UP) {		caps = 1; /* Should characters be upper case? */		numbers = (char *) &HEXnumbers;	}#endif#if 0	 if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */#endif	/*	 * Sorry, we only support 16 digits past the decimal because of our	 * conversion method	 */	if (max > 16)		max = 16;	pow = my_pow10(max);	/* We "cheat" by converting the fractional part to integer by	 * multiplying by a factor of 10	 */	temp = ufvalue;	my_modf(temp, &intpart);	fracpart = my_round(pow * (ufvalue - intpart));	if (fracpart >= pow) {		intpart++;		fracpart -= pow;	}	/* Convert integer part */	do {		temp = intpart * 0.1;		my_modf(temp, &intpart);		index = (int) ((temp - intpart + 0.05) * 10.0);#if 0		index = (int) (((double) (temp*0.1) -intpart +0.05) *10.0);		printf ("%llf, %f, %x\n", temp, intpart, index);#endif		iconvert[iplace++] = numbers[index];	} while (intpart && (iplace < 311));	if (iplace == 311) iplace--;	iconvert[iplace] = 0;	/* Convert fractional part */	if (fracpart) {		do {			temp = fracpart * 0.1;			my_modf(temp, &fracpart);			index = (int) ((temp - fracpart + 0.05) * 10.0);#if 0			index = (int) ((((temp/10) -fracpart) +0.05) *10);			printf ("%lf, %lf, %ld\n", temp, fracpart, index);#endif			fconvert[fplace++] = numbers[index];		} while (fracpart && (fplace < 311));		if (fplace == 311) fplace--;	}	fconvert[fplace] = 0;	/* -1 for decimal point, another -1 if we are printing a sign */	padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);	zpadlen = max - fplace;	if (zpadlen < 0) zpadlen = 0;	if (padlen < 0)		padlen = 0;	if (flags & DP_F_MINUS)		padlen = -padlen; /* Left Justifty */	if ((flags & DP_F_ZERO) && (padlen > 0)) {		if (signvalue) {			dopr_outch(buffer, currlen, maxlen, signvalue);			--padlen;			signvalue = 0;		}		while (padlen > 0) {			dopr_outch(buffer, currlen, maxlen, '0');			--padlen;		}	}	while (padlen > 0) {		dopr_outch(buffer, currlen, maxlen, ' ');		--padlen;	}	if (signvalue)		dopr_outch(buffer, currlen, maxlen, signvalue);	while (iplace > 0)		dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);#ifdef DEBUG_SNPRINTF	printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);#endif	/*	 * Decimal point.  This should probably use locale to find the correct	 * char to print out.	 */	if (max > 0) {		dopr_outch(buffer, currlen, maxlen, '.');		while (zpadlen > 0) {			dopr_outch(buffer, currlen, maxlen, '0');			--zpadlen;		}		while (fplace > 0)			dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);	}	while (padlen < 0) {		dopr_outch(buffer, currlen, maxlen, ' ');		++padlen;	}}/* Yes the following preprocessor conditions really must be a ||. Don't muck * with this. -- tridge * * The logic for these is that we need our own definition if the OS *either* * has no definition of *sprintf, or if it does have one that doesn't work * properly according to the autoconf test. -- mbp */#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)intelinks_vsnprintf(char *str, size_t count, const char *fmt, va_list args){	return dopr(str, count, fmt, args);}#endif#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)intelinks_snprintf(char *str, size_t count, const char *fmt, ...){	size_t ret;	va_list ap;	va_start(ap, fmt);	/* snprintf.h makes this to expand to the right thing. */	ret = vsnprintf(str, count, fmt, ap);	va_end(ap);	return ret;}#endif#endif /* defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF) */#ifndef HAVE_VASPRINTFintelinks_vasprintf(char **ptr, const char *format, va_list ap){	int ret;	va_list ap2;	VA_COPY(ap2, ap);	ret = vsnprintf(NULL, 0, format, ap2);	if (ret <= 0) return ret;	/* Should we use mem_alloc() here instead of malloc() ??? --Zas */	/* No: This is an alternative to the system vasprintf.	 * When the system provides vasprintf, it will use malloc(),	 * which means that the string will need to be freed with free().	 * If we did use mem_alloc here in our alternative to the system	 * vasprintf, we would need to change all users of the memory	 * allocated by vasprintf to take into account whether the system	 * vasprintf (and therefore malloc) or our own vasprintf	 * (and therefore mem_alloc) were used. -- Miciah */	(*ptr) = (char *) malloc(ret + 1);	if (!*ptr) return -1;	VA_COPY(ap2, ap);	return vsnprintf(*ptr, ret + 1, format, ap2);}#endif#ifndef HAVE_ASPRINTFintelinks_asprintf(char **ptr, const char *format, ...){	va_list ap;	int ret;	*ptr = NULL;	va_start(ap, format);	ret = vasprintf(ptr, format, ap);	va_end(ap);	return ret;}#endifunsigned char *asprintfa(const char *fmt, ...){	unsigned char *str;	va_list ap;	va_start(ap, fmt);	str = vasprintfa(fmt, ap);	va_end(ap);	return str;}/* Test program */#ifdef TEST_SNPRINTF#include <math.h>int sprintf(char *str,const char *fmt,...);intmain(void){	char buf1[1024];	char buf2[1024];	char *fp_fmt[] = {		"%1.1f",		"%-1.5f",		"%1.5f",		"%123.9f",		"%10.5f",		"% 10.5f",		"%+22.9f",		"%+4.9f",		"%01.3f",		"%4f",		"%3.1f",		"%3.2f",		"%.0f",		"%f",		"-16.16f",		NULL	};	double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2,			     341.1234, 0203.9, 0.96, 0.996,			     0.9996, 1.996, 4.136, 5.030201, 0};	char *int_fmt[] = {		"%-1.5d",		"%1.5d",		"%123.9d",		"%5.5d",		"%10.5d",		"% 10.5d",		"%+22.33d",		"%01.3d",		"%4d",		"%d",		NULL	};	long int_nums[] = { -1, 134, 91340, 341, 0203, 0};	char *str_fmt[] = {		"10.5s",		"5.10s",		"10.1s",		"0.10s",		"10.0s",		"1.10s",		"%s",		"%.1s",		"%.10s",		"%10s",		NULL	};	char *str_vals[] = {"hello", "a", "", "a longer string", NULL};	int x, y;	int fail = 0;	int num = 0;	printf ("Testing snprintf format codes against system sprintf...\n");	for (x = 0; fp_fmt[x] ; x++) {		for (y = 0; fp_nums[y] != 0 ; y++) {			int l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]);			int l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);			sprintf(buf2, fp_fmt[x], fp_nums[y]);			if (strcmp(buf1, buf2)) {				printf("snprintf doesn't match Format: %s\n\t"				       "snprintf = [%s]\n\t sprintf = [%s]\n",				       fp_fmt[x], buf1, buf2);				fail++;			}			if (l1 != l2) {				printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, fp_fmt[x]);				fail++;			}			num++;		}	}	for (x = 0; int_fmt[x] ; x++) {		for (y = 0; int_nums[y] != 0 ; y++) {			int l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]);			int l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);			sprintf(buf2, int_fmt[x], int_nums[y]);			if (strcmp(buf1, buf2)) {				printf("snprintf doesn't match Format: %s\n\t"				       "snprintf = [%s]\n\t sprintf = [%s]\n",				       int_fmt[x], buf1, buf2);				fail++;			}			if (l1 != l2) {				printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, int_fmt[x]);				fail++;			}			num++;		}	}	for (x = 0; str_fmt[x] ; x++) {		for (y = 0; str_vals[y] != 0 ; y++) {			int l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]);			int l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);			sprintf(buf2, str_fmt[x], str_vals[y]);			if (strcmp(buf1, buf2)) {				printf("snprintf doesn't match Format: %s\n\t"				       "snprintf = [%s]\n\t sprintf = [%s]\n",				       str_fmt[x], buf1, buf2);				fail++;			}			if (l1 != l2) {				printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, str_fmt[x]);				fail++;			}			num++;		}	}	printf ("%d tests failed out of %d.\n", fail, num);	printf("seeing how many digits we support\n");	{		double v0 = 0.12345678901234567890123456789012345678901;		for ( x = 0; x < 100; x++) {			double p = pow(10, x);			double r = v0*p;			snprintf(buf1, sizeof(buf1), "%1.1f", r);			sprintf(buf2,"%1.1f", r);			if (strcmp(buf1, buf2)) {				printf("we seem to support %d digits\n", x-1);				break;			}		}	}	return 0;}#endif /* SNPRINTF_TEST */

⌨️ 快捷键说明

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