📄 snprintf.c
字号:
if (*p->pf == 'g' || *p->pf == 'e') PUT_CHAR('e', p); else PUT_CHAR('E', p); /* the sign of the exp */ if (j >= 0) PUT_CHAR('+', p); else { PUT_CHAR('-', p); j = -j; } tmp = itoa(j); /* pad out to at least two spaces. pad with `0' if the exponent is a single digit. */ if (j <= 9) PUT_CHAR('0', p); /* the exponent */ while (*tmp) { PUT_CHAR(*tmp, p); tmp++; } PAD_LEFT(p);}#endif/* Return a new string with the digits in S grouped according to the locale's grouping info and thousands separator. If no grouping should be performed, this returns NULL; the caller needs to check for it. */static char *groupnum (s) char *s;{ char *se, *ret, *re, *g; int len, slen; if (grouping == 0 || *grouping <= 0 || *grouping == CHAR_MAX) return ((char *)NULL); /* find min grouping to size returned string */ for (len = *grouping, g = grouping; *g; g++) if (*g > 0 && *g < len) len = *g; slen = strlen (s); len = slen / len + 1; ret = (char *)xmalloc (slen + len + 1); re = ret + slen + len; *re = '\0'; g = grouping; se = s + slen; len = *g; while (se > s) { *--re = *--se; /* handle `-' inserted by numtoa() and the fmtu* family here. */ if (se > s && se[-1] == '-') continue; /* begin new group. */ if (--len == 0 && se > s) { *--re = thoussep; len = *++g; /* was g++, but that uses first char twice (glibc bug, too) */ if (*g == '\0') len = *--g; /* use previous grouping */ else if (*g == CHAR_MAX) { do *--re = *--se; while (se > s); break; } } } if (re > ret)#ifdef HAVE_MEMMOVE memmove (ret, re, strlen (re) + 1);#else strcpy (ret, re);#endif return ret;}/* initialize the conversion specifiers */static voidinit_conv_flag (p) struct DATA *p;{ p->flags &= PF_ALLOCBUF; /* preserve PF_ALLOCBUF flag */ p->precision = p->width = NOT_FOUND; p->justify = NOT_FOUND; p->pad = ' ';}static voidinit_data (p, string, length, format, mode) struct DATA *p; char *string; size_t length; const char *format; int mode;{ p->length = length - 1; /* leave room for '\0' */ p->holder = p->base = string; p->pf = format; p->counter = 0; p->flags = (mode == PFM_AS) ? PF_ALLOCBUF : 0;}static int#if defined (__STDC__)vsnprintf_internal(struct DATA *data, char *string, size_t length, const char *format, va_list args)#elsevsnprintf_internal(data, string, length, format, args) struct DATA *data; char *string; size_t length; const char *format; va_list args;#endif{ double d; /* temporary holder */#ifdef HAVE_LONG_DOUBLE long double ld; /* for later */#endif unsigned long ul;#ifdef HAVE_LONG_LONG unsigned long long ull;#endif int state, i, c, n; char *s;#if HANDLE_MULTIBYTE wchar_t *ws; wint_t wc;#endif const char *convstart; int negprec; /* Sanity check, the string length must be >= 0. C99 actually says that LENGTH can be zero here, in the case of snprintf/vsnprintf (it's never 0 in the case of asprintf/vasprintf), and the return value is the number of characters that would have been written. */ if (length < 0) return -1; if (format == 0) return 0; /* Reset these for each call because the locale might have changed. */ decpoint = thoussep = 0; grouping = 0; negprec = 0; for (; c = *(data->pf); data->pf++) { if (c != '%') { PUT_CHAR (c, data); continue; } convstart = data->pf; init_conv_flag (data); /* initialise format flags */ state = 1; for (state = 1; state && *data->pf; ) { c = *(++data->pf); /* fmtend = data->pf */#if defined (FLOATING_POINT) && defined (HAVE_LONG_DOUBLE) if (data->flags & PF_LONGDBL) { switch (c) { case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':# ifdef HAVE_PRINTF_A_FORMAT case 'a': case 'A':# endif STAR_ARGS (data); ld = GETLDOUBLE (data); ldfallback (data, convstart, data->pf, ld); goto conv_break; } }#endif /* FLOATING_POINT && HAVE_LONG_DOUBLE */ switch (c) { /* Parse format flags */ case '\0': /* a NULL here ? ? bail out */ *data->holder = '\0'; return data->counter; break; case '#': data->flags |= PF_ALTFORM; continue; case '0': data->flags |= PF_ZEROPAD; data->pad = '0'; continue; case '*': if (data->flags & PF_DOT) data->flags |= PF_STAR_P; else data->flags |= PF_STAR_W; continue; case '-': if ((data->flags & PF_DOT) == 0) { data->flags |= PF_LADJUST; data->justify = LEFT; } else negprec = 1; continue; case ' ': if ((data->flags & PF_PLUS) == 0) data->flags |= PF_SPACE; continue; case '+': if ((data->flags & PF_DOT) == 0) { data->flags |= PF_PLUS; data->justify = RIGHT; } continue; case '\'': data->flags |= PF_THOUSANDS; continue; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n = 0; do { n = n * 10 + TODIGIT(c); c = *(++data->pf); } while (DIGIT(c)); data->pf--; /* went too far */ if (n < 0) n = 0; if (data->flags & PF_DOT) data->precision = negprec ? NOT_FOUND : n; else data->width = n; continue; /* optional precision */ case '.': data->flags |= PF_DOT; data->precision = 0; continue; /* length modifiers */ case 'h': data->flags |= (data->flags & PF_SHORTINT) ? PF_SIGNEDCHAR : PF_SHORTINT; continue; case 'l': data->flags |= (data->flags & PF_LONGINT) ? PF_LONGLONG : PF_LONGINT; continue; case 'L': data->flags |= PF_LONGDBL; continue; case 'q': data->flags |= PF_LONGLONG; continue; case 'j': data->flags |= PF_INTMAX_T; SET_SIZE_FLAGS(data, intmax_t); continue; case 'z': data->flags |= PF_SIZE_T; SET_SIZE_FLAGS(data, size_t); continue; case 't': data->flags |= PF_PTRDIFF_T; SET_SIZE_FLAGS(data, ptrdiff_t); continue; /* Conversion specifiers */#ifdef FLOATING_POINT case 'f': /* float, double */ case 'F': STAR_ARGS(data); d = GETDOUBLE(data); floating(data, d);conv_break: state = 0; break; case 'g': case 'G': STAR_ARGS(data); DEF_PREC(data); d = GETDOUBLE(data); i = (d != 0.) ? log_10(d) : -1; /* * for '%g|%G' ANSI: use f if exponent * is in the range or [-4,p] exclusively * else use %e|%E */ if (-4 < i && i < data->precision) { /* reset precision */ data->precision -= i + 1; floating(data, d); } else { /* reduce precision by 1 because of leading digit before decimal point in e format. */ data->precision--; exponent(data, d); } state = 0; break; case 'e': case 'E': /* Exponent double */ STAR_ARGS(data); d = GETDOUBLE(data); exponent(data, d); state = 0; break;# ifdef HAVE_PRINTF_A_FORMAT case 'a': case 'A': STAR_ARGS(data); d = GETDOUBLE(data); dfallback(data, convstart, data->pf, d); state = 0; break;# endif /* HAVE_PRINTF_A_FORMAT */#endif /* FLOATING_POINT */ case 'U': data->flags |= PF_LONGINT; /* FALLTHROUGH */ case 'u': STAR_ARGS(data);#ifdef HAVE_LONG_LONG if (data->flags & PF_LONGLONG) { ull = GETARG (unsigned long long); lnumber(data, ull, 10); } else#endif { ul = GETUNSIGNED(data); number(data, ul, 10); } state = 0; break; case 'D': data->flags |= PF_LONGINT; /* FALLTHROUGH */ case 'd': /* decimal */ case 'i': STAR_ARGS(data);#ifdef HAVE_LONG_LONG if (data->flags & PF_LONGLONG) { ull = GETARG (long long); lnumber(data, ull, 10); } else#endif { ul = GETSIGNED(data); number(data, ul, 10); } state = 0; break; case 'o': /* octal */ STAR_ARGS(data);#ifdef HAVE_LONG_LONG if (data->flags & PF_LONGLONG) { ull = GETARG (unsigned long long); lnumber(data, ull, 8); } else#endif { ul = GETUNSIGNED(data); number(data, ul, 8); } state = 0; break; case 'x': case 'X': /* hexadecimal */ STAR_ARGS(data);#ifdef HAVE_LONG_LONG if (data->flags & PF_LONGLONG) { ull = GETARG (unsigned long long); lnumber(data, ull, 16); } else#endif { ul = GETUNSIGNED(data); number(data, ul, 16); } state = 0; break; case 'p': STAR_ARGS(data); ul = (unsigned long)GETARG (void *); pointer(data, ul); state = 0; break;#if HANDLE_MULTIBYTE case 'C': data->flags |= PF_LONGINT; /* FALLTHROUGH */#endif case 'c': /* character */ STAR_ARGS(data);#if HANDLE_MULTIBYTE if (data->flags & PF_LONGINT) { wc = GETARG (wint_t); wchars (data, wc); } else#endif { ul = GETARG (int); PUT_CHAR(ul, data); } state = 0; break;#if HANDLE_MULTIBYTE case 'S': data->flags |= PF_LONGINT; /* FALLTHROUGH */#endif case 's': /* string */ STAR_ARGS(data);#if HANDLE_MULTIBYTE if (data->flags & PF_LONGINT) { ws = GETARG (wchar_t *); wstrings (data, ws); } else#endif { s = GETARG (char *); strings(data, s); } state = 0; break; case 'n':#ifdef HAVE_LONG_LONG if (data->flags & PF_LONGLONG) *(GETARG (long long *)) = data->counter; else#endif if (data->flags & PF_LONGINT) *(GETARG (long *)) = data->counter; else if (data->flags & PF_SHORTINT) *(GETARG (short *)) = data->counter; else *(GETARG (int *)) = data->counter; state = 0; break; case '%': /* nothing just % */ PUT_CHAR('%', data); state = 0; break; default: /* is this an error ? maybe bail out */ state = 0; break; } /* end switch */ } /* end of `%' for loop */ } /* end of format string for loop */ if (data->length >= 0) *data->holder = '\0'; /* the end ye ! */ return data->counter;}#if defined (FLOATING_POINT) && defined (HAVE_LONG_DOUBLE)/* * Printing floating point numbers accurately is an art. I'm not good * at it. Fall back to sprintf for long double formats. */static voidldfallback (data, fs, fe, ld) struct DATA *data; const char *fs, *fe; long double ld;{ register char *x; char fmtbuf[FALLBACK_FMTSIZE], *obuf; int fl; fl = LFALLBACK_BASE + (data->precision < 6 ? 6 : data->precision) + 2; obuf = (char *)xmalloc (fl); fl = fe - fs + 1; strncpy (fmtbuf, fs, fl); fmtbuf[fl] = '\0'; if ((data->flags & PF_STAR_W) && (data->flags & PF_STAR_P)) sprintf (obuf, fmtbuf, data->width, data->precision, ld); else if (data->flags & PF_STAR_W) sprintf (obuf, fmtbuf, data->width, ld); else if (data->flags & PF_STAR_P) sprintf (obuf, fmtbuf, data->precision, ld); else sprintf (obuf, fmtbuf, ld); for (x = obuf; *x; x++) PUT_CHAR (*x, data); xfree (obuf);}#endif /* FLOATING_POINT && HAVE_LONG_DOUBLE */#ifdef FLOATING_POINT/* Used for %a, %A if the libc printf supports them. */static voiddfallback (data, fs, fe, d) struct DATA *data; const char *fs, *fe; double d;{ register char *x;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -