📄 vfprintf.c
字号:
while (*template) { if ((*template == '%') && (*++template != '%')) { ppfs.fmtpos = template; _ppfs_parsespec(&ppfs); /* Can't fail. */ template = ppfs.fmtpos; /* Update to one past spec end. */ if (ppfs.info.width == INT_MIN) { ++count; if (n > 0) { *argtypes++ = PA_INT; --n; } } if (ppfs.info.prec == INT_MIN) { ++count; if (n > 0) { *argtypes++ = PA_INT; --n; } } for (i = 0 ; i < ppfs.num_data_args ; i++) { if ((ppfs.argtype[i]) != __PA_NOARG) { ++count; if (n > 0) { *argtypes++ = ppfs.argtype[i]; --n; } } } } else { ++template; } }#ifdef NL_ARGMAX }#endif /* NL_ARGMAX */ } return count;}#endif/**********************************************************************/#ifdef L__ppfs_initint _ppfs_init(register ppfs_t *ppfs, const char *fmt0){ 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 = fmt0;#ifdef __UCLIBC_MJN3_ONLY__#warning TODO: Make checking of the format string in C locale an option.#endif#ifdef __UCLIBC_HAS_LOCALE__ /* To support old programs, don't check mb validity if in C locale. */ if (((__UCLIBC_CURLOCALE_DATA).encoding) != __ctype_encoding_7_bit) { /* ANSI/ISO C99 requires format string to be a valid multibyte string * beginning and ending in its initial shift state. */ static const char invalid_mbs[] = "Invalid multibyte format string."; mbstate_t mbstate; const char *p; mbstate.__mask = 0; /* Initialize the mbstate. */ p = fmt0; if (mbsrtowcs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) { ppfs->fmtpos = invalid_mbs; return -1; } }#endif /* __UCLIBC_HAS_LOCALE__ */ /* 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 char *fmt = fmt0; while (*fmt) { if ((*fmt == '%') && (*++fmt != '%')) { ppfs->fmtpos = fmt; /* back up to the '%' */ if ((r = _ppfs_parsespec(ppfs)) < 0) { return -1; } fmt = ppfs->fmtpos; /* update to one past end of spec */ } else { ++fmt; } } ppfs->fmtpos = fmt0; /* rewind */ }#ifdef NL_MAX_ARG /* 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_MAX_ARG */ return 0;}#endif/**********************************************************************/#ifdef L__ppfs_prepargsvoid _ppfs_prepargs(register ppfs_t *ppfs, va_list arg){ int i; va_copy(ppfs->arg, arg);#ifdef NL_ARGMAX if ((i = ppfs->maxposarg) > 0) { /* init for positional args */ ppfs->num_data_args = i; ppfs->info.width = ppfs->info.prec = ppfs->maxposarg = 0; _ppfs_setargs(ppfs); ppfs->maxposarg = i; }#endif /* NL_ARGMAX */}#endif/**********************************************************************/#ifdef L__ppfs_setargsvoid _ppfs_setargs(register ppfs_t *ppfs){#ifdef __va_arg_ptr register void **p = ppfs->argptr;#else register argvalue_t *p = ppfs->argvalue;#endif int i;#ifdef NL_ARGMAX if (ppfs->maxposarg == 0) { /* initing for or no pos args */#endif /* NL_ARGMAX */ if (ppfs->info.width == INT_MIN) { ppfs->info.width =#ifdef __va_arg_ptr *(int *)#endif GET_VA_ARG(p,u,unsigned int,ppfs->arg); } if (ppfs->info.prec == INT_MIN) { ppfs->info.prec =#ifdef __va_arg_ptr *(int *)#endif GET_VA_ARG(p,u,unsigned int,ppfs->arg); } i = 0; while (i < ppfs->num_data_args) { switch(ppfs->argtype[i++]) { case (PA_INT|PA_FLAG_LONG_LONG):#ifdef ULLONG_MAX GET_VA_ARG(p,ull,unsigned long long,ppfs->arg); break;#endif case (PA_INT|PA_FLAG_LONG):#if ULONG_MAX != UINT_MAX GET_VA_ARG(p,ul,unsigned long,ppfs->arg); break;#endif case PA_CHAR: /* TODO - be careful */ /* ... users could use above and really want below!! */ case (PA_INT|__PA_FLAG_CHAR):/* TODO -- translate this!!! */ case (PA_INT|PA_FLAG_SHORT): case PA_INT: GET_VA_ARG(p,u,unsigned int,ppfs->arg); break; case PA_WCHAR: /* TODO -- assume int? */ /* we're assuming wchar_t is at least an int */ GET_VA_ARG(p,wc,wchar_t,ppfs->arg); break;#ifdef __STDIO_PRINTF_FLOAT /* PA_FLOAT */ case PA_DOUBLE: GET_VA_ARG(p,d,double,ppfs->arg); break; case (PA_DOUBLE|PA_FLAG_LONG_DOUBLE): GET_VA_ARG(p,ld,long double,ppfs->arg); break;#else /* __STDIO_PRINTF_FLOAT */ case PA_DOUBLE: case (PA_DOUBLE|PA_FLAG_LONG_DOUBLE): assert(0); continue;#endif /* __STDIO_PRINTF_FLOAT */ default: /* TODO -- really need to ensure this can't happen */ assert(ppfs->argtype[i-1] & PA_FLAG_PTR); case PA_POINTER: case PA_STRING: case PA_WSTRING: GET_VA_ARG(p,p,void *,ppfs->arg); break; case __PA_NOARG: continue; } ++p; }#ifdef NL_ARGMAX } else { if (ppfs->info.width == INT_MIN) { ppfs->info.width = (int) GET_ARG_VALUE(p + ppfs->argnumber[0] - 1,u,unsigned int); } if (ppfs->info.prec == INT_MIN) { ppfs->info.prec = (int) GET_ARG_VALUE(p + ppfs->argnumber[1] - 1,u,unsigned int); } }#endif /* NL_ARGMAX */ /* Now we know the width and precision. */ if (ppfs->info.width < 0) { ppfs->info.width = -ppfs->info.width; PRINT_INFO_SET_FLAG(&(ppfs->info),left); PRINT_INFO_CLR_FLAG(&(ppfs->info),space); ppfs->info.pad = ' '; }#if 0 /* NOTE -- keep neg for now so float knows! */ if (ppfs->info.prec < 0) { /* spec says treat as omitted. */ /* so use default prec... 1 for everything but floats and strings. */ ppfs->info.prec = 1; }#endif}#endif/**********************************************************************/#ifdef L__ppfs_parsespec/* Notes: argtype differs from glibc for the following: * mine glibc * lc PA_WCHAR PA_CHAR the standard says %lc means %C * ls PA_WSTRING PA_STRING the standard says %ls means %S * {*}n {*}|PA_FLAG_PTR PA_FLAG_PTR size of n can be qualified *//* TODO: store positions of positional args *//* TODO -- WARNING -- assumes aligned on integer boundaries!!! *//* TODO -- disable if not using positional args!!! */#define _OVERLAPPING_DIFFERENT_ARGS/* TODO -- rethink this -- perhaps we should set to largest type??? */#ifdef _OVERLAPPING_DIFFERENT_ARGS #define PROMOTED_SIZE_OF(X) ((sizeof(X) + sizeof(int) - 1) / sizeof(X))static const short int type_codes[] = { __PA_NOARG, /* must be first entry */ PA_POINTER, PA_STRING, PA_WSTRING, PA_CHAR, PA_INT|PA_FLAG_SHORT, PA_INT, PA_INT|PA_FLAG_LONG, PA_INT|PA_FLAG_LONG_LONG, PA_WCHAR,#ifdef __STDIO_PRINTF_FLOAT /* PA_FLOAT, */ PA_DOUBLE, PA_DOUBLE|PA_FLAG_LONG_DOUBLE,#endif /* __STDIO_PRINTF_FLOAT */};static const unsigned char type_sizes[] = { /* unknown type consumes no arg */ 0, /* must be first entry */ PROMOTED_SIZE_OF(void *), PROMOTED_SIZE_OF(char *), PROMOTED_SIZE_OF(wchar_t *), PROMOTED_SIZE_OF(char), PROMOTED_SIZE_OF(short), PROMOTED_SIZE_OF(int), PROMOTED_SIZE_OF(long),#ifdef ULLONG_MAX PROMOTED_SIZE_OF(long long),#else PROMOTED_SIZE_OF(long), /* TODO -- is this correct? (above too) */#endif PROMOTED_SIZE_OF(wchar_t),#ifdef __STDIO_PRINTF_FLOAT /* PROMOTED_SIZE_OF(float), */ PROMOTED_SIZE_OF(double), PROMOTED_SIZE_OF(long double),#endif /* __STDIO_PRINTF_FLOAT */};static int _promoted_size(int argtype){ register const short int *p; /* note -- since any unrecognized type is treated as a pointer */ p = type_codes + sizeof(type_codes)/sizeof(type_codes[0]); do { if (*--p == argtype) { break; } } while (p > type_codes); return type_sizes[(int)(p - type_codes)];}static int _is_equal_or_bigger_arg(int curtype, int newtype){ /* Quick test */ if (newtype == __PA_NOARG) { return 0; } if ((curtype == __PA_NOARG) || (curtype == newtype)) { return 1; } /* Ok... slot is already filled and types are different in name. */ /* So, compare promoted sizes of curtype and newtype args. */ return _promoted_size(curtype) <= _promoted_size(newtype);}#else#define _is_equal_or_bigger_arg(C,N) (((C) == __PA_NOARG) || ((C) == (N)))#endif#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__/* TODO - do this differently? */static char _bss_custom_printf_spec[MAX_USER_SPEC]; /* 0-init'd for us. */char *_custom_printf_spec = _bss_custom_printf_spec;printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC];printf_function _custom_printf_handler[MAX_USER_SPEC];#endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */extern int _ppfs_parsespec(ppfs_t *ppfs){ register const char *fmt; register const char *p; int preci; int width; int flags; int dataargtype; int i; int dpoint;#ifdef NL_ARGMAX int maxposarg;#endif /* NL_ARGMAX */ int p_m_spec_chars; int n; int argtype[MAX_ARGS_PER_SPEC+2]; int argnumber[3]; /* width, precision, 1st data arg */ static const char spec_flags[] = SPEC_FLAGS; static const char spec_chars[] = SPEC_CHARS;/* TODO: b? */ static const char spec_ranges[] = SPEC_RANGES; static const short spec_or_mask[] = SPEC_OR_MASK; static const short spec_and_mask[] = SPEC_AND_MASK; static const char qual_chars[] = QUAL_CHARS;#ifdef __UCLIBC_HAS_WCHAR__ char buf[32];#endif /* __UCLIBC_HAS_WCHAR__ */ /* WIDE note: we can test against '%' here since we don't allow */ /* WIDE note: other mappings of '%' in the wide char set. */ preci = -1; argnumber[0] = 0; argnumber[1] = 0; argtype[0] = __PA_NOARG; argtype[1] = __PA_NOARG;#ifdef NL_ARGMAX maxposarg = ppfs->maxposarg;#endif /* NL_ARGMAX */#ifdef __UCLIBC_HAS_WCHAR__ /* This is somewhat lame, but saves a lot of code. If we're dealing with * a wide stream, that means the format is a wchar string. So, copy it * char-by-char into a normal char buffer for processing. Make the buffer * (buf) big enough so that any reasonable format specifier will fit. * While there a legal specifiers that won't, the all involve duplicate * flags or outrageous field widths/precisions. */ width = dpoint = 0; if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) { fmt = ppfs->fmtpos; } else { fmt = buf + 1; i = 0; do { if ((buf[i] = (char) (((wchar_t *) ppfs->fmtpos)[i-1])) != (((wchar_t *) ppfs->fmtpos)[i-1]) ) { return -1; } } while (buf[i++]); buf[sizeof(buf)-1] = 0; }#else /* __UCLIBC_HAS_WCHAR__ */ width = flags = dpoint = 0; fmt = ppfs->fmtpos;#endif /* __UCLIBC_HAS_WCHAR__ */ assert(fmt[-1] == '%'); assert(fmt[0] != '%'); /* Process arg pos and/or flags and/or width and/or precision. */ width_precision: p = fmt; if (*fmt == '*') { argtype[-dpoint] = PA_INT; ++fmt; } i = 0; while (isdigit(*fmt)) { if (i < MAX_FIELD_WIDTH) { /* Avoid overflow. */ i = (i * 10) + (*fmt - '0'); } ++fmt; } if (p[-1] == '%') { /* Check for a position. */ /* TODO: if val not in range, then error */#ifdef NL_ARGMAX if ((*fmt == '$') && (i > 0)) {/* Positional spec. */ ++fmt; if (maxposarg == 0) { return -1; } if ((argnumber[2] = i) > maxposarg) { maxposarg = i; } /* Now fall through to check flags. */ } else { if (maxposarg > 0) {#ifdef __UCLIBC_HAS_PRINTF_M_SPEC__#ifdef __UCLIBC_MJN3_ONLY__#warning TODO: Support prec and width for %m when positional args used /* Actually, positional arg processing will fail in general * for specifiers that don't require an arg. */#endif /* __UCLIBC_MJN3_ONLY__ */ if (*fmt == 'm') { goto PREC_WIDTH; }#endif /* __UCLIBC_HAS_PRINTF_M_SPEC__ */ return -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -