@@ -2694,11 +2694,6 @@ unicode_fromformat_write_wcstr(_PyUnicodeWriter *writer, const wchar_t *str,
26942694#define F_SIZE 3
26952695#define F_PTRDIFF 4
26962696#define F_INTMAX 5
2697- static const char * const formats []= {"%d" ,"%ld" ,"%lld" ,"%zd" ,"%td" ,"%jd" };
2698- static const char * const formats_o []= {"%o" ,"%lo" ,"%llo" ,"%zo" ,"%to" ,"%jo" };
2699- static const char * const formats_u []= {"%u" ,"%lu" ,"%llu" ,"%zu" ,"%tu" ,"%ju" };
2700- static const char * const formats_x []= {"%x" ,"%lx" ,"%llx" ,"%zx" ,"%tx" ,"%jx" };
2701- static const char * const formats_X []= {"%X" ,"%lX" ,"%llX" ,"%zX" ,"%tX" ,"%jX" };
27022697
27032698static const char *
27042699unicode_fromformat_arg (_PyUnicodeWriter * writer ,
@@ -2840,47 +2835,44 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer,
28402835case 'd' :case 'i' :
28412836case 'o' :case 'u' :case 'x' :case 'X' :
28422837 {
2843- /* used by sprintf */
28442838char buffer [MAX_INTMAX_CHARS ];
2845- const char * fmt = NULL ;
2846- switch (* f ) {
2847- case 'o' :fmt = formats_o [sizemod ];break ;
2848- case 'u' :fmt = formats_u [sizemod ];break ;
2849- case 'x' :fmt = formats_x [sizemod ];break ;
2850- case 'X' :fmt = formats_X [sizemod ];break ;
2851- default :fmt = formats [sizemod ];break ;
2852- }
2853- int issigned = (* f == 'd' || * f == 'i' );
2839+
2840+ // Fill buffer using sprinf, with one of many possible format
2841+ // strings, like "%llX" for `long long` in hexadecimal.
2842+ // The type/size is in `sizemod`; the format is in `*f`.
2843+
2844+ // Use macros with nested switches to keep the sprintf format strings
2845+ // as compile-time literals, avoiding warnings and maybe allowing
2846+ // optimizations.
2847+
2848+ // `SPRINT` macro does one sprintf
2849+ // Example usage: SPRINT("l", "X", unsigned long) expands to
2850+ // sprintf(buffer, "%" "l" "X", va_arg(*vargs, unsigned long))
2851+ #define SPRINT (SIZE_SPEC ,FMT_CHAR ,TYPE ) \
2852+ sprintf(buffer, "%" SIZE_SPEC FMT_CHAR, va_arg(*vargs, TYPE))
2853+
2854+ // One inner switch to handle all format variants
2855+ #define DO_SPRINTS (SIZE_SPEC ,SIGNED_TYPE ,UNSIGNED_TYPE ) \
2856+ switch (*f) { \
2857+ case 'o': len = SPRINT(SIZE_SPEC, "o", UNSIGNED_TYPE); break; \
2858+ case 'u': len = SPRINT(SIZE_SPEC, "u", UNSIGNED_TYPE); break; \
2859+ case 'x': len = SPRINT(SIZE_SPEC, "x", UNSIGNED_TYPE); break; \
2860+ case 'X': len = SPRINT(SIZE_SPEC, "X", UNSIGNED_TYPE); break; \
2861+ default: len = SPRINT(SIZE_SPEC, "d", SIGNED_TYPE); break; \
2862+ }
2863+
2864+ // Outer switch to handle all the sizes/types
28542865switch (sizemod ) {
2855- case F_LONG :
2856- len = issigned ?
2857- sprintf (buffer ,fmt ,va_arg (* vargs ,long )) :
2858- sprintf (buffer ,fmt ,va_arg (* vargs ,unsigned long ));
2859- break ;
2860- case F_LONGLONG :
2861- len = issigned ?
2862- sprintf (buffer ,fmt ,va_arg (* vargs ,long long )) :
2863- sprintf (buffer ,fmt ,va_arg (* vargs ,unsigned long long));
2864- break ;
2865- case F_SIZE :
2866- len = issigned ?
2867- sprintf (buffer ,fmt ,va_arg (* vargs ,Py_ssize_t )) :
2868- sprintf (buffer ,fmt ,va_arg (* vargs ,size_t ));
2869- break ;
2870- case F_PTRDIFF :
2871- len = sprintf (buffer ,fmt ,va_arg (* vargs ,ptrdiff_t ));
2872- break ;
2873- case F_INTMAX :
2874- len = issigned ?
2875- sprintf (buffer ,fmt ,va_arg (* vargs ,intmax_t )) :
2876- sprintf (buffer ,fmt ,va_arg (* vargs ,uintmax_t ));
2877- break ;
2878- default :
2879- len = issigned ?
2880- sprintf (buffer ,fmt ,va_arg (* vargs ,int )) :
2881- sprintf (buffer ,fmt ,va_arg (* vargs ,unsigned int ));
2882- break ;
2866+ case F_LONG :DO_SPRINTS ("l" ,long ,unsigned long );break ;
2867+ case F_LONGLONG :DO_SPRINTS ("ll" ,long long ,unsigned long long);break ;
2868+ case F_SIZE :DO_SPRINTS ("z" ,Py_ssize_t ,size_t );break ;
2869+ case F_PTRDIFF :DO_SPRINTS ("t" ,ptrdiff_t ,ptrdiff_t );break ;
2870+ case F_INTMAX :DO_SPRINTS ("j" ,intmax_t ,uintmax_t );break ;
2871+ default :DO_SPRINTS ("" ,int ,unsigned int );break ;
28832872 }
2873+ #undef SPRINT
2874+ #undef DO_SPRINTS
2875+
28842876assert (len >=0 );
28852877
28862878int sign = (buffer [0 ]== '-' );