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.
This commit is contained in:
Paul Eggert 2025-01-26 22:15:48 -08:00
parent bcfd4d21b0
commit f885806fdf
8 changed files with 44 additions and 58 deletions

View file

@ -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. */

View file

@ -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, &micro);
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

View file

@ -23,7 +23,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
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 <https://www.gnu.org/licenses/>. */
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 <https://www.gnu.org/licenses/>. */
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 <https://www.gnu.org/licenses/>. */
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)
{

View file

@ -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<num>. */
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,

View file

@ -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);

View file

@ -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);

View file

@ -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)

View file

@ -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);