From 9083b79a4d4b3ecc48e03cb00fcc79ef74ffe878 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 26 Jan 2025 22:15:48 -0800 Subject: [PATCH] Simplify make_formatted_string API From a suggestion by Pip Cet. * src/alloc.c (make_formatted_string): Omit first argument, to simplify the calling convention. All callers changed. * src/doprnt.c (doprnt): Also support %u. Update doc. (cherry picked from commit f885806fdf1aa862ad55d124e9795794fed0b964) --- src/alloc.c | 16 ++++++++++------ src/dbusbind.c | 3 +-- src/doprnt.c | 45 +++++++++++++++++++++++---------------------- src/frame.c | 13 ++++--------- src/image.c | 5 ++--- src/lisp.h | 4 ++-- src/msdos.c | 3 +-- src/xsettings.c | 13 +------------ 8 files changed, 44 insertions(+), 58 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index c4e2ff52015..2c0ccc9dd62 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -2542,19 +2542,23 @@ make_uninit_multibyte_string (EMACS_INT nchars, EMACS_INT nbytes) return make_clear_multibyte_string (nchars, nbytes, false); } -/* Print arguments to BUF according to a FORMAT, then return - a Lisp_String initialized with the data from BUF. */ +/* Return a Lisp_String according to a doprnt-style FORMAT and args. */ Lisp_Object -make_formatted_string (char *buf, const char *format, ...) +make_formatted_string (const char *format, ...) { + char buf[64]; + char *cstr = buf; + ptrdiff_t bufsize = sizeof buf; va_list ap; - int length; va_start (ap, format); - length = vsprintf (buf, format, ap); + ptrdiff_t length = evxprintf (&cstr, &bufsize, buf, -1, format, ap); va_end (ap); - return make_string (buf, length); + Lisp_Object ret = make_string (cstr, length); + if (cstr != buf) + xfree (cstr); + return ret; } /* Pin a unibyte string in place so that it won't move during GC. */ diff --git a/src/dbusbind.c b/src/dbusbind.c index b590a40c4a9..d98009f68b4 100644 --- a/src/dbusbind.c +++ b/src/dbusbind.c @@ -1970,10 +1970,9 @@ syms_of_dbusbind (void) { #ifdef DBUS_VERSION int major, minor, micro; - char s[sizeof ".." + 3 * INT_STRLEN_BOUND (int)]; dbus_get_version (&major, &minor, µ); Vdbus_runtime_version - = make_formatted_string (s, "%d.%d.%d", major, minor, micro); + = make_formatted_string ("%d.%d.%d", major, minor, micro); #else Vdbus_runtime_version = Qnil; #endif diff --git a/src/doprnt.c b/src/doprnt.c index 640349cfec4..335223f972a 100644 --- a/src/doprnt.c +++ b/src/doprnt.c @@ -23,7 +23,7 @@ along with GNU Emacs. If not, see . */ supports the following Emacs-specific features: . For %c conversions, it produces a string with the multibyte representation - of the (`int') argument, suitable for display in an Emacs buffer. + of the ('int') argument, suitable for display in an Emacs buffer. . For %s and %c, when field width is specified (e.g., %25s), it accounts for the display width of each character, according to char-width-table. That @@ -42,8 +42,8 @@ along with GNU Emacs. If not, see . */ overflow ptrdiff_t or size_t, to avoid producing strings longer than what Emacs can handle. - OTOH, this function supports only a small subset of the standard C formatted - output facilities. E.g., %u is not supported, precision is ignored + On the other hand, this function supports only a small subset of the + standard C formatted output facilities. E.g., precision is ignored in %s and %c conversions, and %lld does not necessarily work and code should use something like %"pM"d with intmax_t instead. (See below for the detailed documentation of what is supported.) @@ -57,16 +57,17 @@ along with GNU Emacs. If not, see . */ also supports the following %-sequences: %s means print a string argument. - %S is treated as %s, for loose compatibility with `Fformat_message'. - %d means print a `signed int' argument in decimal. - %o means print an `unsigned int' argument in octal. - %x means print an `unsigned int' argument in hex. - %e means print a `double' argument in exponential notation. - %f means print a `double' argument in decimal-point notation. - %g means print a `double' argument in exponential notation + %S is treated as %s, for loose compatibility with 'Fformat_message'. + %d means print a 'signed int' argument in decimal. + %o means print an 'unsigned int' argument in octal. + %u means print an 'unsigned int' argument in decimal. + %x means print an 'unsigned int' argument in hex. + %e means print a 'double' argument in exponential notation. + %f means print a 'double' argument in decimal-point notation. + %g means print a 'double' argument in exponential notation or in decimal-point notation, depending on the value; this is often (though not always) the shorter of the two notations. - %c means print a `signed int' argument as a single character. + %c means print a 'signed int' argument as a single character. %% means produce a literal % character. A %-sequence other than %% may contain optional flags, width, precision, @@ -82,18 +83,18 @@ along with GNU Emacs. If not, see . */ The + flag character inserts a + before any positive number, while a space inserts a space before any positive number; these flags only affect %d, %o, %x, %e, %f, and %g sequences. The - and 0 flags affect the width specifier, - as described below. For signed numerical arguments only, the ` ' (space) + as described below. For signed numerical arguments only, the ' ' (space) flag causes the result to be prefixed with a space character if it does not start with a sign (+ or -). - The l (lower-case letter ell) length modifier is a `long' data type + The l (lower-case letter ell) length modifier is a 'long' data type modifier: it is supported for %d, %o, and %x conversions of integral arguments, must immediately precede the conversion specifier, and means that - the respective argument is to be treated as `long int' or `unsigned long + the respective argument is to be treated as 'long int' or 'unsigned long int'. Similarly, the value of the pD macro means to use ptrdiff_t, the value of the pI macro means to use EMACS_INT or EMACS_UINT, the value of the PRIdMAX etc. macros means to use intmax_t or uintmax_t, - and the empty length modifier means `int' or `unsigned int'. + and the empty length modifier means 'int' or 'unsigned int'. The width specifier supplies a lower limit for the length of the printed representation. The padding, if any, normally goes on the left, but it goes @@ -162,16 +163,15 @@ doprnt_non_null_end (char *buffer, ptrdiff_t bufsize, char const *format, return nbytes; } -/* Generate output from a format-spec FORMAT, +/* Format to BUFFER (of positive size BUFSIZE) data formated by FORMAT, terminated at either the first NUL or (if FORMAT_END is non-null and there are no NUL bytes between FORMAT and FORMAT_END) - terminated at position FORMAT_END. + terminated at position FORMAT_END. AP specifies format arguments. (*FORMAT_END is not part of the format, but must exist and be readable.) - Output goes in BUFFER, which has room for BUFSIZE chars. - BUFSIZE must be positive. If the output does not fit, truncate it - to fit and return BUFSIZE - 1; if this truncates a multibyte - sequence, store '\0' into the sequence's first byte. - Returns the number of bytes stored into BUFFER, excluding + If the output does not fit, truncate it to fit and return BUFSIZE - 1; + if this truncates a multibyte sequence, + store '\0' into the sequence's first byte. + Return the number of bytes stored into BUFFER, excluding the terminating null byte. Output is always null-terminated. String arguments are passed as C strings. Integers are passed as C integers. @@ -349,6 +349,7 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char *format, goto doit; case 'o': + case 'u': case 'x': switch (length_modifier) { diff --git a/src/frame.c b/src/frame.c index 3820f102c0e..f2d47d9bc51 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1283,8 +1283,6 @@ static struct frame * make_terminal_frame (struct terminal *terminal, Lisp_Object parent, Lisp_Object params) { - char name[sizeof "F" + INT_STRLEN_BOUND (tty_frame_count)]; - if (!terminal->name) error ("Terminal is not live, can't create new frames on it"); @@ -1364,7 +1362,7 @@ make_terminal_frame (struct terminal *terminal, Lisp_Object parent, XSETFRAME (frame, f); Vframe_list = Fcons (frame, Vframe_list); - fset_name (f, make_formatted_string (name, "F%"PRIdMAX, ++tty_frame_count)); + fset_name (f, make_formatted_string ("F%"PRIdMAX, ++tty_frame_count)); SET_FRAME_VISIBLE (f, true); @@ -3504,14 +3502,12 @@ set_term_frame_name (struct frame *f, Lisp_Object name) /* If NAME is nil, set the name to F. */ if (NILP (name)) { - char namebuf[sizeof "F" + INT_STRLEN_BOUND (tty_frame_count)]; - /* Check for no change needed in this very common case before we do any consing. */ if (frame_name_fnn_p (SSDATA (f->name), SBYTES (f->name))) return; - name = make_formatted_string (namebuf, "F%"PRIdMAX, ++tty_frame_count); + name = make_formatted_string ("F%"PRIdMAX, ++tty_frame_count); } else { @@ -4938,7 +4934,6 @@ gui_report_frame_params (struct frame *f, Lisp_Object *alistptr) { Lisp_Object tem; uintmax_t w; - char buf[INT_BUFSIZE_BOUND (w)]; /* Represent negative positions (off the top or left screen edge) in a way that Fmodify_frame_parameters will understand correctly. */ @@ -4989,7 +4984,7 @@ gui_report_frame_params (struct frame *f, Lisp_Object *alistptr) warnings. */ w = (uintptr_t) FRAME_NATIVE_WINDOW (f); store_in_alist (alistptr, Qwindow_id, - make_formatted_string (buf, "%"PRIuMAX, w)); + make_formatted_string ("%"PRIuMAX, w)); #ifdef HAVE_X_WINDOWS #ifdef USE_X_TOOLKIT /* Tooltip frame may not have this widget. */ @@ -4997,7 +4992,7 @@ gui_report_frame_params (struct frame *f, Lisp_Object *alistptr) #endif w = (uintptr_t) FRAME_OUTER_WINDOW (f); store_in_alist (alistptr, Qouter_window_id, - make_formatted_string (buf, "%"PRIuMAX, w)); + make_formatted_string ("%"PRIuMAX, w)); #endif store_in_alist (alistptr, Qicon_name, f->icon_name); store_in_alist (alistptr, Qvisibility, diff --git a/src/image.c b/src/image.c index de6955c2a47..4350c415d9c 100644 --- a/src/image.c +++ b/src/image.c @@ -12601,7 +12601,6 @@ static bool gs_load (struct frame *f, struct image *img) { uintmax_t printnum1, printnum2; - char buffer[sizeof " " + 2 * INT_STRLEN_BOUND (intmax_t)]; Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width; Lisp_Object frame; double in_width, in_height; @@ -12653,13 +12652,13 @@ gs_load (struct frame *f, struct image *img) printnum1 = FRAME_X_DRAWABLE (f); printnum2 = img->pixmap; window_and_pixmap_id - = make_formatted_string (buffer, "%"PRIuMAX" %"PRIuMAX, + = make_formatted_string ("%"PRIuMAX" %"PRIuMAX, printnum1, printnum2); printnum1 = FRAME_FOREGROUND_PIXEL (f); printnum2 = FRAME_BACKGROUND_PIXEL (f); pixel_colors - = make_formatted_string (buffer, "%"PRIuMAX" %"PRIuMAX, + = make_formatted_string ("%"PRIuMAX" %"PRIuMAX, printnum1, printnum2); XSETFRAME (frame, f); diff --git a/src/lisp.h b/src/lisp.h index 28fa4c8037e..2faad895133 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -4592,8 +4592,8 @@ extern Lisp_Object make_uninit_bool_vector (EMACS_INT); extern Lisp_Object bool_vector_fill (Lisp_Object, Lisp_Object); extern AVOID string_overflow (void); extern Lisp_Object make_string (const char *, ptrdiff_t); -extern Lisp_Object make_formatted_string (char *, const char *, ...) - ATTRIBUTE_FORMAT_PRINTF (2, 3); +extern Lisp_Object make_formatted_string (const char *, ...) + ATTRIBUTE_FORMAT_PRINTF (1, 2); extern Lisp_Object make_unibyte_string (const char *, ptrdiff_t); extern ptrdiff_t vectorlike_nbytes (const union vectorlike_header *hdr); diff --git a/src/msdos.c b/src/msdos.c index 63a5400bc7d..95eb6453040 100644 --- a/src/msdos.c +++ b/src/msdos.c @@ -531,7 +531,6 @@ vga_installed (void) void dos_set_window_size (int *rows, int *cols) { - char video_name[30]; union REGS regs; Lisp_Object video_mode; int video_mode_value, have_vga = 0; @@ -547,7 +546,7 @@ dos_set_window_size (int *rows, int *cols) use that mode. */ video_mode = Fsymbol_value (Fintern_soft (make_formatted_string - (video_name, "screen-dimensions-%dx%d", + ("screen-dimensions-%dx%d", *rows, *cols), Qnil)); if (FIXNUMP (video_mode) diff --git a/src/xsettings.c b/src/xsettings.c index 76f9fae62fe..30b5ed258ae 100644 --- a/src/xsettings.c +++ b/src/xsettings.c @@ -927,17 +927,6 @@ apply_xft_settings (Display_Info *dpyinfo, static char const format[] = "Antialias: %d, Hinting: %d, RGBA: %d, LCDFilter: %d, " "Hintstyle: %d, DPI: %f"; - enum - { - d_formats = 5, - d_growth = INT_BUFSIZE_BOUND (int) - sizeof "%d", - lf_formats = 1, - max_f_integer_digits = DBL_MAX_10_EXP + 1, - f_precision = 6, - lf_growth = (sizeof "-." + max_f_integer_digits + f_precision - - sizeof "%f") - }; - char buf[sizeof format + d_formats * d_growth + lf_formats * lf_growth]; #ifdef HAVE_XFT XftDefaultSet (dpyinfo->display, pat); #else @@ -946,7 +935,7 @@ apply_xft_settings (Display_Info *dpyinfo, store_config_changed_event (Qfont_render, XCAR (dpyinfo->name_list_element)); Vxft_settings - = make_formatted_string (buf, format, + = make_formatted_string (format, oldsettings.aa, oldsettings.hinting, oldsettings.rgba, oldsettings.lcdfilter, oldsettings.hintstyle, oldsettings.dpi); -- 2.39.5