There is a simplification and optimization for __vfprintf() from android pointed out by tedu:
https://github.com/aosp-mirror/platform_bionic/commit/5305a4d4a723b06494b93f2df81733b83a0c46d3 If we only support UTF-8 and ASCII, we do not need complicated multibyte decoding to recognize a '%' in the format string. In his commit message, enh claims that there is a 10x speedup. In my own benchmarking on amd64, a speedup between 1.5x and 5x seems to be more realistic. The code does get significantly simpler, so I think it might be worth it. The android commit has lots of style noise. There is a second part to it that fixes some missing error checking in vfwprintf similar to some of schwarze's fixes in vfprintf.c r1.71. I'll send that one out in a second mail as it's completely independent. Do we want this? Index: lib/libc/stdio/vfprintf.c =================================================================== RCS file: /var/cvs/src/lib/libc/stdio/vfprintf.c,v retrieving revision 1.77 diff -u -p -r1.77 vfprintf.c --- lib/libc/stdio/vfprintf.c 29 Aug 2016 12:20:57 -0000 1.77 +++ lib/libc/stdio/vfprintf.c 14 Nov 2017 08:07:27 -0000 @@ -279,8 +279,6 @@ __vfprintf(FILE *fp, const char *fmt0, _ int width; /* width from format (%8d), or 0 */ int prec; /* precision from format; <0 for N/A */ char sign; /* sign prefix (' ', '+', '-', or \0) */ - wchar_t wc; - mbstate_t ps; #ifdef FLOATING_POINT /* * We can decompose the printed representation of floating @@ -481,25 +479,13 @@ __vfprintf(FILE *fp, const char *fmt0, _ convbuf = NULL; #endif - memset(&ps, 0, sizeof(ps)); /* * Scan the format for conversions (`%' character). */ for (;;) { - size_t len; + for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) + continue; - cp = fmt; - while ((len = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) != 0) { - if (len == (size_t)-1 || len == (size_t)-2) { - ret = -1; - goto error; - } - fmt += len; - if (wc == '%') { - fmt--; - break; - } - } if (fmt != cp) { ptrdiff_t m = fmt - cp; if (m < 0 || m > INT_MAX - ret) @@ -507,7 +493,7 @@ __vfprintf(FILE *fp, const char *fmt0, _ PRINT(cp, m); ret += m; } - if (len == 0) + if (ch == '\0') goto done; fmt++; /* skip over '%' */ @@ -852,7 +838,9 @@ fp_common: xdigs = xdigs_lower; ox[1] = 'x'; goto nosign; - case 's': + case 's': { + size_t len; + #ifdef PRINTF_WIDE_CHAR if (flags & LONGINT) { wchar_t *wcp; @@ -893,6 +881,7 @@ fp_common: goto overflow; size = (int)len; sign = '\0'; + } break; case 'U': flags |= LONGINT; @@ -1156,8 +1145,6 @@ __find_arguments(const char *fmt0, va_li int tablemax; /* largest used index in table */ int nextarg; /* 1-based argument index */ int ret = 0; /* return value */ - wchar_t wc; - mbstate_t ps; /* * Add an argument type to the table, expanding if necessary. @@ -1211,25 +1198,14 @@ __find_arguments(const char *fmt0, va_li tablemax = 0; nextarg = 1; memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE); - memset(&ps, 0, sizeof(ps)); /* * Scan the format for conversions (`%' character). */ for (;;) { - size_t len; - - cp = fmt; - while ((len = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) != 0) { - if (len == (size_t)-1 || len == (size_t)-2) - return (-1); - fmt += len; - if (wc == '%') { - fmt--; - break; - } - } - if (len == 0) + for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) + continue; + if (ch == '\0') goto done; fmt++; /* skip over '%' */