📄 vfprintf.c
字号:
static const wchar_t prefix[] = L"+\0-\0 \0000x\0000X";#endif /* L_vfprintf */ enum { PREFIX_PLUS = 0, PREFIX_MINUS = 2, PREFIX_SPACE = 4, PREFIX_LWR_X = 6, PREFIX_UPR_X = 9, PREFIX_NONE = 11 };#ifdef __va_arg_ptr const void * const *argptr;#else const void * argptr[MAX_ARGS_PER_SPEC];#endif int *argtype;#ifdef __UCLIBC_HAS_WCHAR__ const wchar_t *ws = NULL; mbstate_t mbstate;#endif /* __UCLIBC_HAS_WCHAR__ */ size_t slen;#ifdef L_vfprintf#define SLEN slen#else size_t SLEN; wchar_t wbuf[2];#endif int base; int numpad; int alphacase; int numfill = 0; /* TODO: fix */ int prefix_num = PREFIX_NONE; char padchar = ' ';#ifdef __UCLIBC_MJN3_ONLY__#warning TODO: Determine appropriate buf size.#endif /* __UCLIBC_MJN3_ONLY__ */ /* TODO: buf needs to be big enough for any possible error return strings * and also for any locale-grouped long long integer strings generated. * This should be large enough for any of the current archs/locales, but * eventually this should be handled robustly. */ char buf[128];#ifdef NDEBUG _ppfs_parsespec(ppfs);#else if (_ppfs_parsespec(ppfs) < 0) { /* TODO: just for debugging */ abort(); }#endif _ppfs_setargs(ppfs); argtype = ppfs->argtype + ppfs->argnumber[2] - 1; /* Deal with the argptr vs argvalue issue. */#ifdef __va_arg_ptr argptr = (const void * const *) ppfs->argptr;#ifdef NL_ARGMAX if (ppfs->maxposarg > 0) { /* Using positional args... */ argptr += ppfs->argnumber[2] - 1; }#endif /* NL_ARGMAX */#else /* Need to build a local copy... */ { register argvalue_t *p = ppfs->argvalue; int i;#ifdef NL_ARGMAX if (ppfs->maxposarg > 0) { /* Using positional args... */ p += ppfs->argnumber[2] - 1; }#endif /* NL_ARGMAX */ for (i = 0 ; i < ppfs->num_data_args ; i++ ) { argptr[i] = (void *) p++; } }#endif { register char *s = NULL; /* TODO: Should s be unsigned char * ? */ if (ppfs->conv_num == CONV_n) { _store_inttype(*(void **)*argptr, ppfs->info._flags & __PA_INTMASK, (intmax_t) (*count)); return 0; } if (ppfs->conv_num <= CONV_i) { /* pointer or (un)signed int */ alphacase = __UIM_LOWER;#ifdef __UCLIBC_MJN3_ONLY__#ifdef L_vfprintf#warning CONSIDER: Should we ignore these flags if stub locale? What about custom specs?#endif#endif /* __UCLIBC_MJN3_ONLY__ */ if ((base = spec_base[(int)(ppfs->conv_num - CONV_p)]) == 10) { if (PRINT_INFO_FLAG_VAL(&(ppfs->info),group)) { alphacase = __UIM_GROUP; } if (PRINT_INFO_FLAG_VAL(&(ppfs->info),i18n)) { alphacase |= 0x80; } } if (ppfs->conv_num <= CONV_u) { /* pointer or unsigned int */ if (ppfs->conv_num == CONV_X) { alphacase = __UIM_UPPER; } if (ppfs->conv_num == CONV_p) { /* pointer */ prefix_num = PREFIX_LWR_X; } else { /* unsigned int */ } } else { /* signed int */ base = -base; } if (ppfs->info.prec < 0) { /* Ignore '0' flag if prec specified. */ padchar = ppfs->info.pad; }#ifdef __UCLIBC_MJN3_ONLY__#ifdef L_vfprintf#warning CONSIDER: If using outdigits and/or grouping, how should we interpret precision?#endif#endif /* __UCLIBC_MJN3_ONLY__ */ s = _uintmaxtostr(buf + sizeof(buf) - 1, (uintmax_t) _load_inttype(*argtype & __PA_INTMASK, *argptr, base), base, alphacase); if (ppfs->conv_num > CONV_u) { /* signed int */ if (*s == '-') { PRINT_INFO_SET_FLAG(&(ppfs->info),showsign); ++s; /* handle '-' in the prefix string */ prefix_num = PREFIX_MINUS; } else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),showsign)) { prefix_num = PREFIX_PLUS; } else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),space)) { prefix_num = PREFIX_SPACE; } } slen = (char *)(buf + sizeof(buf) - 1) - s;#ifdef L_vfwprintf { const char *q = s; mbstate.__mask = 0; /* Initialize the mbstate. */ SLEN = mbsrtowcs(NULL, &q, 0, &mbstate); }#endif numfill = ((ppfs->info.prec < 0) ? 1 : ppfs->info.prec); if (PRINT_INFO_FLAG_VAL(&(ppfs->info),alt)) { if (ppfs->conv_num <= CONV_x) { /* x or p */ prefix_num = PREFIX_LWR_X; } if (ppfs->conv_num == CONV_X) { prefix_num = PREFIX_UPR_X; } if ((ppfs->conv_num == CONV_o) && (numfill <= SLEN)) { numfill = ((*s == '0') ? 1 : SLEN + 1); } } if (*s == '0') { if (prefix_num >= PREFIX_LWR_X) { prefix_num = PREFIX_NONE; } if (ppfs->conv_num == CONV_p) {/* null pointer */ s = "(nil)";#ifdef L_vfwprintf SLEN =#endif slen = 5; numfill = 0; } else if (numfill == 0) { /* if precision 0, no output */#ifdef L_vfwprintf SLEN =#endif slen = 0; } } numfill = ((numfill > SLEN) ? numfill - SLEN : 0); } else if (ppfs->conv_num <= CONV_A) { /* floating point */#ifdef __STDIO_PRINTF_FLOAT *count += _fpmaxtostr(stream, (__fpmax_t) (PRINT_INFO_FLAG_VAL(&(ppfs->info),is_long_double) ? *(long double *) *argptr : (long double) (* (double *) *argptr)), &ppfs->info, FP_OUT ); return 0;#else /* __STDIO_PRINTF_FLOAT */ return -1; /* TODO -- try to continue? */#endif /* __STDIO_PRINTF_FLOAT */ } else if (ppfs->conv_num <= CONV_S) { /* wide char or string */#ifdef L_vfprintf#ifdef __UCLIBC_HAS_WCHAR__ mbstate.__mask = 0; /* Initialize the mbstate. */ if (ppfs->conv_num == CONV_S) { /* wide string */ if (!(ws = *((const wchar_t **) *argptr))) { goto NULL_STRING; } /* We use an awful uClibc-specific hack here, passing * (char*) &ws as the conversion destination. This signals * uClibc's wcsrtombs that we want a "restricted" length * such that the mbs fits in a buffer of the specified * size with no partial conversions. */ if ((slen = wcsrtombs((char *) &ws, &ws, /* Use awful hack! */ ((ppfs->info.prec >= 0) ? ppfs->info.prec : SIZE_MAX), &mbstate)) == ((size_t)-1) ) { return -1; /* EILSEQ */ } } else { /* wide char */ s = buf; slen = wcrtomb(s, (*((const wchar_t *) *argptr)), &mbstate); if (slen == ((size_t)-1)) { return -1; /* EILSEQ */ } s[slen] = 0; /* TODO - Is this necessary? */ }#else /* __UCLIBC_HAS_WCHAR__ */ return -1;#endif /* __UCLIBC_HAS_WCHAR__ */ } else if (ppfs->conv_num <= CONV_s) { /* char or string */ if (ppfs->conv_num == CONV_s) { /* string */ s = *((char **) (*argptr)); if (s) {#ifdef __UCLIBC_HAS_PRINTF_M_SPEC__ SET_STRING_LEN:#endif slen = strnlen(s, ((ppfs->info.prec >= 0) ? ppfs->info.prec : SIZE_MAX)); } else {#ifdef __UCLIBC_HAS_WCHAR__ NULL_STRING:#endif s = "(null)"; slen = 6; } } else { /* char */ s = buf; *s = (unsigned char)(*((const int *) *argptr)); s[1] = 0; slen = 1; }#else /* L_vfprintf */ if (ppfs->conv_num == CONV_S) { /* wide string */ ws = *((wchar_t **) (*argptr)); if (!ws) { goto NULL_STRING; } SLEN = wcsnlen(ws, ((ppfs->info.prec >= 0) ? ppfs->info.prec : SIZE_MAX)); } else { /* wide char */ *wbuf = (wchar_t)(*((const wint_t *) *argptr)); CHAR_CASE: ws = wbuf; wbuf[1] = 0; SLEN = 1; } } else if (ppfs->conv_num <= CONV_s) { /* char or string */ if (ppfs->conv_num == CONV_s) { /* string */#ifdef __UCLIBC_MJN3_ONLY__#warning TODO: Fix %s for vfwprintf... output upto illegal sequence?#endif /* __UCLIBC_MJN3_ONLY__ */ s = *((char **) (*argptr)); if (s) {#ifdef __UCLIBC_HAS_PRINTF_M_SPEC__ SET_STRING_LEN:#endif /* We use an awful uClibc-specific hack here, passing * (wchar_t*) &mbstate as the conversion destination. * This signals uClibc's mbsrtowcs that we want a * "restricted" length such that the mbs fits in a buffer * of the specified size with no partial conversions. */ { const char *q = s; mbstate.__mask = 0; /* Initialize the mbstate. */ SLEN = mbsrtowcs((wchar_t *) &mbstate, &q, ((ppfs->info.prec >= 0) ? ppfs->info.prec : SIZE_MAX), &mbstate); } if (SLEN == ((size_t)(-1))) { return -1; /* EILSEQ */ } } else { NULL_STRING: s = "(null)"; SLEN = slen = 6; } } else { /* char */ *wbuf = btowc( (unsigned char)(*((const int *) *argptr)) ); goto CHAR_CASE; }#endif /* L_vfprintf */#ifdef __UCLIBC_HAS_PRINTF_M_SPEC__ } else if (ppfs->conv_num == CONV_m) { s = _glibc_strerror_r(errno, buf, sizeof(buf)); goto SET_STRING_LEN;#endif } else {#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ assert(ppfs->conv_num == CONV_custom0); s = _custom_printf_spec; do { if (*s == ppfs->info.spec) { int rv; /* TODO -- check return value for sanity? */ rv = (*_custom_printf_handler [(int)(s-_custom_printf_spec)]) (stream, &ppfs->info, argptr); if (rv < 0) { return -1; } *count += rv; return 0; } } while (++s < (_custom_printf_spec + MAX_USER_SPEC));#endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */ assert(0); return -1; }#ifdef __UCLIBC_MJN3_ONLY__#ifdef L_vfprintf#warning CONSIDER: If using outdigits and/or grouping, how should we pad?#endif#endif /* __UCLIBC_MJN3_ONLY__ */ { size_t t; t = SLEN + numfill; if (prefix_num != PREFIX_NONE) { t += ((prefix_num < PREFIX_LWR_X) ? 1 : 2); } numpad = ((ppfs->info.width > t) ? (ppfs->info.width - t) : 0); *count += t + numpad; } if (padchar == '0') { /* TODO: check this */ numfill += numpad; numpad = 0; } /* Now handle the output itself. */ if (!PRINT_INFO_FLAG_VAL(&(ppfs->info),left)) { _charpad(stream, ' ', numpad); numpad = 0; } OUTPUT(stream, prefix + prefix_num); _charpad(stream, '0', numfill);#ifdef L_vfprintf#ifdef __UCLIBC_HAS_WCHAR__ if (!ws) { assert(s); _outnstr(stream, s, slen); } else { /* wide string */ size_t t; mbstate.__mask = 0; /* Initialize the mbstate. */ while (slen) { t = (slen <= sizeof(buf)) ? slen : sizeof(buf); t = wcsrtombs(buf, &ws, t, &mbstate); assert (t != ((size_t)(-1))); _outnstr(stream, buf, t); slen -= t; } }#else /* __UCLIBC_HAS_WCHAR__ */ _outnstr(stream, s, slen);#endif /* __UCLIBC_HAS_WCHAR__ */#else /* L_vfprintf */ if (!ws) { assert(s); _outnstr(stream, s, SLEN); } else { _outnwcs(stream, ws, SLEN); }#endif /* L_vfprintf */ _charpad(stream, ' ', numpad); } return 0;}int VFPRINTF (FILE * __restrict stream, register const FMT_TYPE * __restrict format, va_list arg){ ppfs_t ppfs; int count, r; register const FMT_TYPE *s; __STDIO_AUTO_THREADLOCK_VAR; __STDIO_AUTO_THREADLOCK(stream); count = 0; s = format; if #ifdef L_vfprintf (!__STDIO_STREAM_IS_NARROW_WRITING(stream) && __STDIO_STREAM_TRANS_TO_WRITE(stream, __FLAG_NARROW))#else (!__STDIO_STREAM_IS_WIDE_WRITING(stream) && __STDIO_STREAM_TRANS_TO_WRITE(stream, __FLAG_WIDE))#endif { count = -1; } else if (_PPFS_init(&ppfs, format) < 0) { /* Bad format string. */ OUTNSTR(stream, (const FMT_TYPE *) ppfs.fmtpos, STRLEN((const FMT_TYPE *)(ppfs.fmtpos)));#if defined(L_vfprintf) && !defined(NDEBUG) fprintf(stderr,"\nIMbS: \"%s\"\n\n", format);#endif count = -1; } else { _ppfs_prepargs(&ppfs, arg); /* This did a va_copy!!! */ do { while (*format && (*format != '%')) { ++format; } if (format-s) { /* output any literal text in format string */ if ( (r = OUTNSTR(stream, s, format-s)) < 0) { count = -1; break; } count += r; } if (!*format) { /* we're done */ break; } if (format[1] != '%') { /* if we get here, *format == '%' */ /* TODO: _do_one_spec needs to know what the output funcs are!!! */ ppfs.fmtpos = (const char *)(++format); /* TODO: check -- should only fail on stream error */ if ( (r = _do_one_spec(stream, &ppfs, &count)) < 0) { count = -1; break; } s = format = (const FMT_TYPE *) ppfs.fmtpos; } else { /* %% means literal %, so start new string */ s = ++format; ++format; } } while (1); va_end(ppfs.arg); /* Need to clean up after va_copy! */ }/* #if defined(L_vfprintf) && defined(__UCLIBC_HAS_WCHAR__) *//* DONE: *//* #endif */ __STDIO_AUTO_THREADUNLOCK(stream); return count;}#endif/**********************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -