📄 snprintf.c
字号:
while (padlen < 0) { total += dopr_outch (buffer, currlen, maxlen, ' '); ++padlen; } return total;}/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */static int fmtint (char *buffer, size_t *currlen, size_t maxlen, LLONG value, int base, int min, int max, int flags){ int signvalue = 0; unsigned LLONG uvalue; char convert[24]; int place = 0; int spadlen = 0; /* amount to space pad */ int zpadlen = 0; /* amount to zero pad */ const char *digits; int total = 0; if (max < 0) max = 0; uvalue = value; if(!(flags & DP_F_UNSIGNED)) { if( value < 0 ) { signvalue = '-'; uvalue = -value; } else if (flags & DP_F_PLUS) /* Do a sign (+/i) */ signvalue = '+'; else if (flags & DP_F_SPACE) signvalue = ' '; } if (flags & DP_F_UP) /* Should characters be upper case? */ digits = "0123456789ABCDEF"; else digits = "0123456789abcdef"; do { convert[place++] = digits[uvalue % (unsigned)base]; uvalue = (uvalue / (unsigned)base ); } while(uvalue && (place < sizeof (convert))); if (place == sizeof (convert)) place--; convert[place] = 0; zpadlen = max - place; spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); if (zpadlen < 0) zpadlen = 0; if (spadlen < 0) spadlen = 0; if (flags & DP_F_ZERO) { zpadlen = MAX(zpadlen, spadlen); spadlen = 0; } if (flags & DP_F_MINUS) spadlen = -spadlen; /* Left Justifty */#ifdef DEBUG_SNPRINTF dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", zpadlen, spadlen, min, max, place));#endif /* Spaces */ while (spadlen > 0) { total += dopr_outch (buffer, currlen, maxlen, ' '); --spadlen; } /* Sign */ if (signvalue) total += dopr_outch (buffer, currlen, maxlen, signvalue); /* Zeros */ if (zpadlen > 0) { while (zpadlen > 0) { total += dopr_outch (buffer, currlen, maxlen, '0'); --zpadlen; } } /* Digits */ while (place > 0) total += dopr_outch (buffer, currlen, maxlen, convert[--place]); /* Left Justified spaces */ while (spadlen < 0) { total += dopr_outch (buffer, currlen, maxlen, ' '); ++spadlen; } return total;}static LDOUBLE abs_val (LDOUBLE value){ LDOUBLE result = value; if (value < 0) result = -value; return result;}static LDOUBLE pow10_int (int exp){ LDOUBLE result = 1; while (exp) { result *= 10; exp--; } return result;}static LLONG round_int (LDOUBLE value){ LLONG intpart; intpart = value; value = value - intpart; if (value >= 0.5) intpart++; return intpart;}static int fmtfp (char *buffer, size_t *currlen, size_t maxlen, LDOUBLE fvalue, int min, int max, int flags){ int signvalue = 0; LDOUBLE ufvalue; char iconvert[24]; char fconvert[24]; int iplace = 0; int fplace = 0; int padlen = 0; /* amount to pad */ int zpadlen = 0; int total = 0; LLONG intpart; LLONG fracpart; LLONG mask10; int leadingfrac0s = 0; /* zeros at the start of fractional part */ int omitzeros = 0; int omitcount = 0; /* * 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 = abs_val (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? */#endif intpart = ufvalue; /* With %g precision is the number of significant digits, which includes the digits in intpart. */ if (flags & DP_F_FP_G) { if (intpart != 0) { /* For each digit of INTPART, print one less fractional digit. */ LLONG temp = intpart; for (temp = intpart; temp != 0; temp /= 10) --max; if (max < 0) max = 0; } else { /* For each leading 0 in fractional part, print one more fractional digit. */ LDOUBLE temp; if (ufvalue != 0) for (temp = ufvalue; temp < 0.1; temp *= 10) ++max; } } /* C99: trailing zeros are removed from the fractional portion of the result unless the # flag is specified */ if ((flags & DP_F_FP_G) && !(flags & DP_F_NUM)) omitzeros = 1;#if SIZEOF_LONG_LONG > 0# define MAX_DIGITS 18 /* grok more digits with long long */#else# define MAX_DIGITS 9 /* just long */#endif /* * Sorry, we only support several digits past the decimal because of * our conversion method */ if (max > MAX_DIGITS) max = MAX_DIGITS; /* Factor of 10 with the needed number of digits, e.g. 1000 for max==3 */ mask10 = pow10_int (max); /* We "cheat" by converting the fractional part to integer by * multiplying by a factor of 10 */ fracpart = round_int (mask10 * (ufvalue - intpart)); if (fracpart >= mask10) { intpart++; fracpart -= mask10; } else if (fracpart != 0) /* If fracpart has less digits than the 10* mask, we need to manually insert leading 0s. For example 2.01's fractional part requires one leading zero to distinguish it from 2.1. */ while (fracpart < mask10 / 10) { ++leadingfrac0s; mask10 /= 10; }#ifdef DEBUG_SNPRINTF dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));#endif /* Convert integer part */ do { iconvert[iplace++] = '0' + intpart % 10; intpart = (intpart / 10); } while(intpart && (iplace < sizeof(iconvert))); if (iplace == sizeof(iconvert)) iplace--; iconvert[iplace] = 0; /* Convert fractional part */ do { fconvert[fplace++] = '0' + fracpart % 10; fracpart = (fracpart / 10); } while(fracpart && (fplace < sizeof(fconvert))); while (leadingfrac0s-- > 0 && fplace < sizeof(fconvert)) fconvert[fplace++] = '0'; if (fplace == sizeof(fconvert)) fplace--; fconvert[fplace] = 0; if (omitzeros) while (omitcount < fplace && fconvert[omitcount] == '0') ++omitcount; /* -1 for decimal point, another -1 if we are printing a sign */ padlen = min - iplace - (max - omitcount) - 1 - ((signvalue) ? 1 : 0); if (!omitzeros) 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) { total += dopr_outch (buffer, currlen, maxlen, signvalue); --padlen; signvalue = 0; } while (padlen > 0) { total += dopr_outch (buffer, currlen, maxlen, '0'); --padlen; } } while (padlen > 0) { total += dopr_outch (buffer, currlen, maxlen, ' '); --padlen; } if (signvalue) total += dopr_outch (buffer, currlen, maxlen, signvalue); while (iplace > 0) total += dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]); /* * Decimal point. This should probably use locale to find the correct * char to print out. */ if (max > 0 && (fplace > omitcount || zpadlen > 0)) { total += dopr_outch (buffer, currlen, maxlen, '.'); while (fplace > omitcount) total += dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]); } while (zpadlen > 0) { total += dopr_outch (buffer, currlen, maxlen, '0'); --zpadlen; } while (padlen < 0) { total += dopr_outch (buffer, currlen, maxlen, ' '); ++padlen; } return total;}static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c){ if (*currlen + 1 < maxlen) buffer[(*currlen)++] = c; return 1;}#ifndef HAVE_VSNPRINTFint vsnprintf (char *str, size_t count, const char *fmt, va_list args){ if (str != NULL) str[0] = 0; return dopr(str, count, fmt, args);}#endif /* !HAVE_VSNPRINTF */#ifndef HAVE_SNPRINTFint snprintf (char *str, size_t count, const char *fmt,...){ va_list ap; int total; va_start (ap, fmt); total = vsnprintf (str, count, fmt, ap); va_end (ap); return total;}#endif /* !HAVE_SNPRINTF */#endif /* !HAVE_SNPRINTF || !HAVE_VSNPRINTF */#ifdef TEST_SNPRINTF# ifndef LONG_STRING# define LONG_STRING 1024# endifint main (void){ char buf1[LONG_STRING]; char buf2[LONG_STRING]; char *fp_fmt[] = { /* %f formats */ "%f", "%-1.5f", "%1.5f", "%123.9f", "%10.5f", "% 10.5f", "%+22.9f", "%+4.9f", "%01.3f", "%4f", "%3.1f", "%3.2f", "%.0f", "%.1f", "%#10.1f",#if SIZEOF_LONG_LONG != 0 "%.16f", "%18.16f", "%-16.16f",#endif /* %g formats */ "%g", "%1.5g", "%-1.5g", "%.9g", "%123.9g", "%#123.9g",#if SIZEOF_LONG_LONG != 0 "%.16g", "%20.16g",#endif NULL }; double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996, 0.9996, 1.996, 4.136, 0.00205, 0.0001, 321.000009, 0}; char *int_fmt[] = { "%-1.5d", "%1.5d", "%123.9d", "%5.5d", "%10.5d", "% 10.5d", "%+22.33d", "%01.3d", "%4d", NULL }; long int_nums[] = { -1, 134, 91340, 341, 0203, 0};#if SIZEOF_LONG_LONG != 0 char *llong_fmt[] = { "%lld", "%llu", "%-1.5lld", "%-1.5llu", "%1.5lld", "%1.5llu", "%123.9lld", "%123.9llu", "%5.5lld", "%5.5llu", "%10.5lld", "%10.5llu", "% 10.5lld", "% 10.5llu", "%+22.33lld", "%+22.33llu", "%01.3lld", "%01.3llu", "%4lld", "%4llu", NULL }; long long llong_nums[] = { ~(long long)0, /* all-1 bit pattern */ (~(unsigned long long)0) >> 1, /* largest signed long long */ /* random... */ -150, 134, 91340, 341, 0 };#endif int x, y; int fail = 0; int num = 0; printf ("Testing snprintf format codes against system sprintf...\n"); for (x = 0; fp_fmt[x] != NULL ; x++) for (y = 0; fp_nums[y] != 0 ; y++) { 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\tsnprintf = %s\n\tsprintf = %s\n", fp_fmt[x], buf1, buf2); fail++; } num++; } for (x = 0; int_fmt[x] != NULL ; x++) for (y = 0; int_nums[y] != 0 ; y++) { 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\tsnprintf = %s\n\tsprintf = %s\n", int_fmt[x], buf1, buf2); fail++; } num++; }#if SIZEOF_LONG_LONG != 0 for (x = 0; llong_fmt[x] != NULL ; x++) for (y = 0; llong_nums[y] != 0 ; y++) { snprintf (buf1, sizeof (buf1), llong_fmt[x], llong_nums[y]); sprintf (buf2, llong_fmt[x], llong_nums[y]); if (strcmp (buf1, buf2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n", llong_fmt[x], buf1, buf2); fail++; } num++; }#endif printf ("%d tests failed out of %d.\n", fail, num); return 0;}#endif /* TEST_SNPRINTF */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -