📄 vfprintf.c
字号:
} maxposarg = 0; /* Possible redundant store, but cuts size. */ if ((fmt > p) && (*p != '0')) { goto PREC_WIDTH; } fmt = p; /* Back up for possible '0's flag. */ /* Now fall through to check flags. */ }#else /* NL_ARGMAX */ if (*fmt == '$') { /* Positional spec. */ return -1; } if ((fmt > p) && (*p != '0')) { goto PREC_WIDTH; } fmt = p; /* Back up for possible '0's flag. */ /* Now fall through to check flags. */#endif /* NL_ARGMAX */ restart_flags: /* Process flags. */ i = 1; p = spec_flags; do { if (*fmt == *p++) { ++fmt; flags |= i; goto restart_flags; } i += i; /* Better than i <<= 1 for bcc */ } while (*p); i = 0; /* If '+' then ignore ' ', and if '-' then ignore '0'. */ /* Note: Need to ignore '0' when prec is an arg with val < 0, */ /* but that test needs to wait until the arg is retrieved. */ flags &= ~((flags & (FLAG_PLUS|FLAG_MINUS)) >> 1); /* Note: Ignore '0' when prec is specified < 0 too (in printf). */ if (fmt[-1] != '%') { /* If we've done anything, loop for width. */ goto width_precision; } } PREC_WIDTH: if (*p == '*') { /* Prec or width takes an arg. */#ifdef NL_ARGMAX if (maxposarg) { if ((*fmt++ != '$') || (i <= 0)) { /* Using pos args and no $ or invalid arg number. */ return -1; } argnumber[-dpoint] = i; } else#endif /* NL_ARGMAX */ if (++p != fmt) { /* Not using pos args but digits followed *. */ return -1; } i = INT_MIN; } if (!dpoint) { width = i; if (*fmt == '.') { ++fmt; dpoint = -1; /* To use as default precison. */ goto width_precision; } } else { preci = i; } /* Process qualifier. */ p = qual_chars; do { if (*fmt == *p) { ++fmt; break; } } while (*++p); if ((p - qual_chars < 2) && (*fmt == *p)) { p += ((sizeof(qual_chars)-2) / 2); ++fmt; } dataargtype = ((int)(p[(sizeof(qual_chars)-2) / 2])) << 8; /* Process conversion specifier. */ if (!*fmt) { return -1; } p = spec_chars; do { if (*fmt == *p) { p_m_spec_chars = p - spec_chars; if ((p_m_spec_chars >= CONV_c) && (dataargtype & PA_FLAG_LONG)) { p_m_spec_chars -= 2; /* lc -> C and ls -> S */ } ppfs->conv_num = p_m_spec_chars; p = spec_ranges-1; while (p_m_spec_chars > *++p) {} i = p - spec_ranges; argtype[2] = (dataargtype | spec_or_mask[i]) & spec_and_mask[i]; p = spec_chars; break; } } while(*++p); ppfs->info.spec = *fmt; ppfs->info.prec = preci; ppfs->info.width = width; ppfs->info.pad = ((flags & FLAG_ZERO) ? '0' : ' '); ppfs->info._flags = (flags & ~FLAG_ZERO) | (dataargtype & __PA_INTMASK); ppfs->num_data_args = 1; if (!*p) {#ifdef __UCLIBC_HAS_PRINTF_M_SPEC__ if (*fmt == 'm') { ppfs->conv_num = CONV_m; ppfs->num_data_args = 0; goto DONE; }#endif#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ /* Handle custom arg -- WARNING -- overwrites p!!! */ ppfs->conv_num = CONV_custom0; p = _custom_printf_spec; do { if (*p == *fmt) { if ((ppfs->num_data_args = ((*_custom_printf_arginfo[(int)(p-_custom_printf_spec)]) (&(ppfs->info), MAX_ARGS_PER_SPEC, argtype+2))) > MAX_ARGS_PER_SPEC) { break; /* Error -- too many args! */ } goto DONE; } } while (++p < (_custom_printf_spec + MAX_USER_SPEC));#endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */ /* Otherwise error. */ return -1; } #if defined(__UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__) || defined(__UCLIBC_HAS_PRINTF_M_SPEC__) DONE:#endif#ifdef NL_ARGMAX if (maxposarg > 0) { i = 0; do { /* Update maxposarg and check that NL_ARGMAX is not exceeded. */ n = ((i <= 2) ? (ppfs->argnumber[i] = argnumber[i]) : argnumber[2] + (i-2)); if (n > maxposarg) { if ((maxposarg = n) > NL_ARGMAX) { return -1; } } --n; /* Record argtype with largest size (current, new). */ if (_is_equal_or_bigger_arg(ppfs->argtype[n], argtype[i])) { ppfs->argtype[n] = argtype[i]; } } while (++i < ppfs->num_data_args + 2); } else {#endif /* NL_ARGMAX */ ppfs->argnumber[2] = 1; memcpy(ppfs->argtype, argtype + 2, ppfs->num_data_args * sizeof(int));#ifdef NL_ARGMAX } ppfs->maxposarg = maxposarg;#endif /* NL_ARGMAX */#ifdef __UCLIBC_HAS_WCHAR__ if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) { ppfs->fmtpos = ++fmt; } else { ppfs->fmtpos = (const char *) (((const wchar_t *)(ppfs->fmtpos)) + (fmt - buf) ); }#else /* __UCLIBC_HAS_WCHAR__ */ ppfs->fmtpos = ++fmt;#endif /* __UCLIBC_HAS_WCHAR__ */ return ppfs->num_data_args + 2;}#endif/**********************************************************************/#ifdef L_register_printf_function#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__int register_printf_function(int spec, printf_function handler, printf_arginfo_function arginfo){ register char *r; register char *p; if (spec && (arginfo != NULL)) { /* TODO -- check if spec is valid char */ r = NULL; p = _custom_printf_spec + MAX_USER_SPEC; do { --p; if (!*p) { r = p; }#ifdef __BCC__ else /* bcc generates less code with fall-through */#endif if (*p == spec) { r = p; p = _custom_printf_spec; } } while (p > _custom_printf_spec); if (r) { if (handler) { *r = spec; _custom_printf_handler[(int)(r - p)] = handler; _custom_printf_arginfo[(int)(r - p)] = arginfo; } else { *r = 0; } return 0; } /* TODO -- if asked to unregister a non-existent spec, return what? */ } return -1;}#endif#endif/**********************************************************************/#if defined(L_vfprintf) || defined(L_vfwprintf)/* We only support ascii digits (or their USC equivalent codes) in * precision and width settings in *printf (wide) format strings. * In other words, we don't currently support glibc's 'I' flag. * We do accept it, but it is currently ignored. */static void _charpad(FILE * __restrict stream, int padchar, size_t numpad);#ifdef L_vfprintf#define VFPRINTF vfprintf#define FMT_TYPE char#define OUTNSTR _outnstr#define STRLEN strlen#define _PPFS_init _ppfs_init#define OUTPUT(F,S) __fputs_unlocked(S,F)/* #define _outnstr(stream, string, len) __stdio_fwrite(string, len, stream) */#define _outnstr(stream, string, len) ((len > 0) ? __stdio_fwrite(string, len, stream) : 0)#define FP_OUT _fp_out_narrow#ifdef __STDIO_PRINTF_FLOATstatic void _fp_out_narrow(FILE *fp, intptr_t type, intptr_t len, intptr_t buf){ if (type & 0x80) { /* Some type of padding needed. */ int buflen = strlen((const char *) buf); if ((len -= buflen) > 0) { _charpad(fp, (type & 0x7f), len); } len = buflen; } OUTNSTR(fp, (const char *) buf, len);}#endif /* __STDIO_PRINTF_FLOAT */#else /* L_vfprintf */#define VFPRINTF vfwprintf#define FMT_TYPE wchar_t#define OUTNSTR _outnwcs#define STRLEN wcslen#define _PPFS_init _ppwfs_init#define OUTPUT(F,S) fputws(S,F)#define _outnwcs(stream, wstring, len) _wstdio_fwrite(wstring, len, stream)#define FP_OUT _fp_out_widestatic void _outnstr(FILE *stream, const char *s, size_t wclen){ /* NOTE!!! len here is the number of wchars we want to generate!!! */ wchar_t wbuf[64]; mbstate_t mbstate; size_t todo, r; mbstate.__mask = 0; todo = wclen; while (todo) { r = mbsrtowcs(wbuf, &s, ((todo <= sizeof(wbuf)/sizeof(wbuf[0])) ? todo : sizeof(wbuf)/sizeof(wbuf[0])), &mbstate); assert(((ssize_t)r) > 0); _outnwcs(stream, wbuf, r); todo -= r; }}#ifdef __STDIO_PRINTF_FLOAT#ifdef __UCLIBC_MJN3_ONLY__#warning TODO: Move defines from _fpmaxtostr. Put them in a common header.#endif/* The following defines are from _fpmaxtostr.*/#define DIGITS_PER_BLOCK 9#define NUM_DIGIT_BLOCKS ((DECIMAL_DIG+DIGITS_PER_BLOCK-1)/DIGITS_PER_BLOCK)#define BUF_SIZE ( 3 + NUM_DIGIT_BLOCKS * DIGITS_PER_BLOCK )static void _fp_out_wide(FILE *fp, intptr_t type, intptr_t len, intptr_t buf){ wchar_t wbuf[BUF_SIZE]; const char *s = (const char *) buf; int i; if (type & 0x80) { /* Some type of padding needed */ int buflen = strlen(s); if ((len -= buflen) > 0) { _charpad(fp, (type & 0x7f), len); } len = buflen; } if (len > 0) { i = 0; do {#ifdef __LOCALE_C_ONLY wbuf[i] = s[i];#else /* __LOCALE_C_ONLY */#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ if (s[i] == ',') { wbuf[i] = __UCLIBC_CURLOCALE_DATA.thousands_sep_wc; } else#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */ if (s[i] == '.') { wbuf[i] = __UCLIBC_CURLOCALE_DATA.decimal_point_wc; } else { wbuf[i] = s[i]; }#endif /* __LOCALE_C_ONLY */ } while (++i < len); OUTNSTR(fp, wbuf, len); }}#endif /* __STDIO_PRINTF_FLOAT */static int _ppwfs_init(register ppfs_t *ppfs, const wchar_t *fmt0){ static const wchar_t invalid_wcs[] = L"Invalid wide format string."; int r; /* First, zero out everything... argnumber[], argtype[], argptr[] */ memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */#ifdef NL_ARGMAX --ppfs->maxposarg; /* set to -1 */#endif /* NL_ARGMAX */ ppfs->fmtpos = (const char *) fmt0; ppfs->info._flags = FLAG_WIDESTREAM; { mbstate_t mbstate; const wchar_t *p; mbstate.__mask = 0; /* Initialize the mbstate. */ p = fmt0; if (wcsrtombs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) { ppfs->fmtpos = (const char *) invalid_wcs; return -1; } } /* now set all argtypes to no-arg */ {#if 1 /* TODO - use memset here since already "paid for"? */ register int *p = ppfs->argtype; r = MAX_ARGS; do { *p++ = __PA_NOARG; } while (--r);#else /* TODO -- get rid of this?? */ register char *p = (char *) ((MAX_ARGS-1) * sizeof(int)); do { *((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG; p -= sizeof(int); } while (p);#endif } /* * Run through the entire format string to validate it and initialize * the positional arg numbers (if any). */ { register const wchar_t *fmt = fmt0; while (*fmt) { if ((*fmt == '%') && (*++fmt != '%')) { ppfs->fmtpos = (const char *) fmt; /* back up to the '%' */ if ((r = _ppfs_parsespec(ppfs)) < 0) { return -1; } fmt = (const wchar_t *) ppfs->fmtpos; /* update to one past end of spec */ } else { ++fmt; } } ppfs->fmtpos = (const char *) fmt0; /* rewind */ }#ifdef NL_ARGMAX /* If we have positional args, make sure we know all the types. */ { register int *p = ppfs->argtype; r = ppfs->maxposarg; while (--r >= 0) { if ( *p == __PA_NOARG ) { /* missing arg type!!! */ return -1; } ++p; } }#endif /* NL_ARGMAX */ return 0;}#endif /* L_vfprintf */static void _charpad(FILE * __restrict stream, int padchar, size_t numpad){ /* TODO -- Use a buffer to cut down on function calls... */ FMT_TYPE pad[1]; *pad = padchar; while (numpad) { OUTNSTR(stream, pad, 1); --numpad; }}/* TODO -- Dynamically allocate work space to accomodate stack-poor archs? */static int _do_one_spec(FILE * __restrict stream, register ppfs_t *ppfs, int *count){ static const char spec_base[] = SPEC_BASE;#ifdef L_vfprintf static const char prefix[] = "+\0-\0 \0000x\0000X"; /* 0 2 4 6 9 11*/#else /* L_vfprintf */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -