📄 vfprintf.c
字号:
LABEL (form_unknown): if (spec == L_('\0')) { /* The format string ended before the specifier is complete. */ done = -1; goto all_done; } /* If we are in the fast loop force entering the complicated one. */ goto do_positional; } /* The format is correctly handled. */ ++nspecs_done; if (__builtin_expect (workstart != NULL, 0)) free (workstart); workstart = NULL; /* Look for next format specifier. */#ifdef COMPILE_WPRINTF f = __find_specwc ((end_of_spec = ++f));#else f = __find_specmb ((end_of_spec = ++f), &mbstate);#endif /* Write the following constant string. */ outstring (end_of_spec, f - end_of_spec); } while (*f != L_('\0')); /* Unlock stream and return. */ goto all_done; /* Here starts the more complex loop to handle positional parameters. */do_positional: { /* Array with information about the needed arguments. This has to be dynamically extensible. */ size_t nspecs = 0; size_t nspecs_max = 32; /* A more or less arbitrary start value. */ struct printf_spec *specs = alloca (nspecs_max * sizeof (struct printf_spec)); /* The number of arguments the format string requests. This will determine the size of the array needed to store the argument attributes. */ size_t nargs = 0; int *args_type; union printf_arg *args_value = NULL; /* Positional parameters refer to arguments directly. This could also determine the maximum number of arguments. Track the maximum number. */ size_t max_ref_arg = 0; /* Just a counter. */ size_t cnt; if (grouping == (const char *) -1) {#ifdef COMPILE_WPRINTF thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_THOUSANDS_SEP_WC);#else thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);#endif grouping = _NL_CURRENT (LC_NUMERIC, GROUPING); if (*grouping == '\0' || *grouping == CHAR_MAX) grouping = NULL; } for (f = lead_str_end; *f != L_('\0'); f = specs[nspecs++].next_fmt) { if (nspecs >= nspecs_max) { /* Extend the array of format specifiers. */ struct printf_spec *old = specs; nspecs_max *= 2; specs = alloca (nspecs_max * sizeof (struct printf_spec)); if (specs == &old[nspecs]) /* Stack grows up, OLD was the last thing allocated; extend it. */ nspecs_max += nspecs_max / 2; else { /* Copy the old array's elements to the new space. */ memcpy (specs, old, nspecs * sizeof (struct printf_spec)); if (old == &specs[nspecs]) /* Stack grows down, OLD was just below the new SPECS. We can use that space when the new space runs out. */ nspecs_max += nspecs_max / 2; } } /* Parse the format specifier. */#ifdef COMPILE_WPRINTF nargs += __parse_one_specwc (f, nargs, &specs[nspecs], &max_ref_arg);#else nargs += __parse_one_specmb (f, nargs, &specs[nspecs], &max_ref_arg, &mbstate);#endif } /* Determine the number of arguments the format string consumes. */ nargs = MAX (nargs, max_ref_arg); /* Allocate memory for the argument descriptions. */ args_type = alloca (nargs * sizeof (int)); memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0', nargs * sizeof (int)); args_value = alloca (nargs * sizeof (union printf_arg)); /* XXX Could do sanity check here: If any element in ARGS_TYPE is still zero after this loop, format is invalid. For now we simply use 0 as the value. */ /* Fill in the types of all the arguments. */ for (cnt = 0; cnt < nspecs; ++cnt) { /* If the width is determined by an argument this is an int. */ if (specs[cnt].width_arg != -1) args_type[specs[cnt].width_arg] = PA_INT; /* If the precision is determined by an argument this is an int. */ if (specs[cnt].prec_arg != -1) args_type[specs[cnt].prec_arg] = PA_INT; switch (specs[cnt].ndata_args) { case 0: /* No arguments. */ break; case 1: /* One argument; we already have the type. */ args_type[specs[cnt].data_arg] = specs[cnt].data_arg_type; break; default: /* We have more than one argument for this format spec. We must call the arginfo function again to determine all the types. */ (void) (*__printf_arginfo_table[specs[cnt].info.spec]) (&specs[cnt].info, specs[cnt].ndata_args, &args_type[specs[cnt].data_arg]); break; } } /* Now we know all the types and the order. Fill in the argument values. */ for (cnt = 0; cnt < nargs; ++cnt) switch (args_type[cnt]) {#define T(tag, mem, type) \ case tag: \ args_value[cnt].mem = va_arg (ap_save, type); \ break T (PA_CHAR, pa_int, int); /* Promoted. */ T (PA_WCHAR, pa_wchar, wint_t); T (PA_INT|PA_FLAG_SHORT, pa_int, int); /* Promoted. */ T (PA_INT, pa_int, int); T (PA_INT|PA_FLAG_LONG, pa_long_int, long int); T (PA_INT|PA_FLAG_LONG_LONG, pa_long_long_int, long long int); T (PA_FLOAT, pa_double, double); /* Promoted. */ T (PA_DOUBLE, pa_double, double); T (PA_DOUBLE|PA_FLAG_LONG_DOUBLE, pa_long_double, long double); T (PA_STRING, pa_string, const char *); T (PA_WSTRING, pa_wstring, const wchar_t *); T (PA_POINTER, pa_pointer, void *);#undef T default: if ((args_type[cnt] & PA_FLAG_PTR) != 0) args_value[cnt].pa_pointer = va_arg (ap_save, void *); else args_value[cnt].pa_long_double = 0.0; break; case -1: /* Error case. Not all parameters appear in N$ format strings. We have no way to determine their type. */ assert (s->_flags2 & _IO_FLAGS2_FORTIFY); __libc_fatal ("*** invalid %N$ use detected ***\n"); } /* Now walk through all format specifiers and process them. */ for (; (size_t) nspecs_done < nspecs; ++nspecs_done) {#undef REF#if defined HAVE_SUBTRACT_LOCAL_LABELS && defined SHARED# define REF(Name) &&do2_##Name - &&do_form_unknown#else# define REF(Name) &&do2_##Name#endif#undef LABEL#define LABEL(Name) do2_##Name STEP4_TABLE; int is_negative; union { unsigned long long int longlong; unsigned long int word; } number; int base; union printf_arg the_arg; CHAR_T *string; /* Pointer to argument string. */ /* Fill variables from values in struct. */ int alt = specs[nspecs_done].info.alt; int space = specs[nspecs_done].info.space; int left = specs[nspecs_done].info.left; int showsign = specs[nspecs_done].info.showsign; int group = specs[nspecs_done].info.group; int is_long_double = specs[nspecs_done].info.is_long_double; int is_short = specs[nspecs_done].info.is_short; int is_char = specs[nspecs_done].info.is_char; int is_long = specs[nspecs_done].info.is_long; int width = specs[nspecs_done].info.width; int prec = specs[nspecs_done].info.prec; int use_outdigits = specs[nspecs_done].info.i18n; char pad = specs[nspecs_done].info.pad; CHAR_T spec = specs[nspecs_done].info.spec; CHAR_T *workstart = NULL; /* Fill in last information. */ if (specs[nspecs_done].width_arg != -1) { /* Extract the field width from an argument. */ specs[nspecs_done].info.width = args_value[specs[nspecs_done].width_arg].pa_int; if (specs[nspecs_done].info.width < 0) /* If the width value is negative left justification is selected and the value is taken as being positive. */ { specs[nspecs_done].info.width *= -1; left = specs[nspecs_done].info.left = 1; } width = specs[nspecs_done].info.width; } if (specs[nspecs_done].prec_arg != -1) { /* Extract the precision from an argument. */ specs[nspecs_done].info.prec = args_value[specs[nspecs_done].prec_arg].pa_int; if (specs[nspecs_done].info.prec < 0) /* If the precision is negative the precision is omitted. */ specs[nspecs_done].info.prec = -1; prec = specs[nspecs_done].info.prec; } /* Maybe the buffer is too small. */ if (MAX (prec, width) + 32 > (int) (sizeof (work_buffer) / sizeof (CHAR_T))) { if (__libc_use_alloca ((MAX (prec, width) + 32) * sizeof (CHAR_T))) workend = ((CHAR_T *) alloca ((MAX (prec, width) + 32) * sizeof (CHAR_T)) + (MAX (prec, width) + 32)); else { workstart = (CHAR_T *) malloc ((MAX (prec, width) + 32) * sizeof (CHAR_T)); workend = workstart + (MAX (prec, width) + 32); } } /* Process format specifiers. */ while (1) { JUMP (spec, step4_jumps); process_arg ((&specs[nspecs_done])); process_string_arg ((&specs[nspecs_done])); LABEL (form_unknown): { extern printf_function **__printf_function_table; int function_done; printf_function *function; unsigned int i; const void **ptr; function = (__printf_function_table == NULL ? NULL : __printf_function_table[specs[nspecs_done].info.spec]); if (function == NULL) function = &printf_unknown; ptr = alloca (specs[nspecs_done].ndata_args * sizeof (const void *)); /* Fill in an array of pointers to the argument values. */ for (i = 0; i < specs[nspecs_done].ndata_args; ++i) ptr[i] = &args_value[specs[nspecs_done].data_arg + i]; /* Call the function. */ function_done = (*function) (s, &specs[nspecs_done].info, ptr); /* If an error occurred we don't have information about # of chars. */ if (function_done < 0) { done = -1; goto all_done; } done += function_done; } break; } if (__builtin_expect (workstart != NULL, 0)) free (workstart); workstart = NULL; /* Write the following constant string. */ outstring (specs[nspecs_done].end_of_fmt, specs[nspecs_done].next_fmt - specs[nspecs_done].end_of_fmt); } }all_done: if (__builtin_expect (workstart != NULL, 0)) free (workstart); /* Unlock the stream. */ _IO_funlockfile (s); _IO_cleanup_region_end (0); return done;}/* Handle an unknown format specifier. This prints out a canonicalized representation of the format spec itself. */static intprintf_unknown (FILE *s, const struct printf_info *info, const void *const *args){ int done = 0; CHAR_T work_buffer[MAX (info->width, info->spec) + 32]; CHAR_T *const workend = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)]; register CHAR_T *w; outchar (L_('%')); if (info->alt) outchar (L_('#')); if (info->group) outchar (L_('\'')); if (info->showsign) outchar (L_('+')); else if (info->space) outchar (L_(' ')); if (info->left) outchar (L_('-')); if (info->pad == L_('0')) outchar (L_('0')); if (info->i18n) outchar (L_('I')); if (info->width != 0) { w = _itoa_word (info->width, workend, 10, 0); while (w < workend) outchar (*w++); } if (info->prec != -1)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -