From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Paul Eggert Newsgroups: gmane.emacs.bugs Subject: bug#43439: [PATCH] doprnt improvements Date: Tue, 15 Sep 2020 18:50:51 -0700 Message-ID: <20200916015051.20517-1-eggert@cs.ucla.edu> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="8598"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Paul Eggert To: 43439@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Wed Sep 16 03:52:12 2020 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kIMcF-00023x-4m for geb-bug-gnu-emacs@m.gmane-mx.org; Wed, 16 Sep 2020 03:52:11 +0200 Original-Received: from localhost ([::1]:60732 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kIMcD-0007zw-MP for geb-bug-gnu-emacs@m.gmane-mx.org; Tue, 15 Sep 2020 21:52:09 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:42110) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kIMc6-0007zm-C9 for bug-gnu-emacs@gnu.org; Tue, 15 Sep 2020 21:52:02 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:49475) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1kIMc6-0001V1-3I for bug-gnu-emacs@gnu.org; Tue, 15 Sep 2020 21:52:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1kIMc6-0003we-1u for bug-gnu-emacs@gnu.org; Tue, 15 Sep 2020 21:52:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Paul Eggert Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Wed, 16 Sep 2020 01:52:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 43439 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch X-Debbugs-Original-To: bug-gnu-emacs@gnu.org Original-Received: via spool by submit@debbugs.gnu.org id=B.160022107015100 (code B ref -1); Wed, 16 Sep 2020 01:52:01 +0000 Original-Received: (at submit) by debbugs.gnu.org; 16 Sep 2020 01:51:10 +0000 Original-Received: from localhost ([127.0.0.1]:32788 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1kIMbF-0003vU-IE for submit@debbugs.gnu.org; Tue, 15 Sep 2020 21:51:10 -0400 Original-Received: from lists.gnu.org ([209.51.188.17]:55378) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1kIMb9-0003vF-MF for submit@debbugs.gnu.org; Tue, 15 Sep 2020 21:51:07 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:41940) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kIMb9-0007vf-Dd for bug-gnu-emacs@gnu.org; Tue, 15 Sep 2020 21:51:03 -0400 Original-Received: from zimbra.cs.ucla.edu ([131.179.128.68]:41204) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kIMb6-0001NC-2X for bug-gnu-emacs@gnu.org; Tue, 15 Sep 2020 21:51:02 -0400 Original-Received: from localhost (localhost [127.0.0.1]) by zimbra.cs.ucla.edu (Postfix) with ESMTP id DE6EB1600F3 for ; Tue, 15 Sep 2020 18:50:56 -0700 (PDT) Original-Received: from zimbra.cs.ucla.edu ([127.0.0.1]) by localhost (zimbra.cs.ucla.edu [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id KRDrXpZrnvBq; Tue, 15 Sep 2020 18:50:54 -0700 (PDT) Original-Received: from localhost (localhost [127.0.0.1]) by zimbra.cs.ucla.edu (Postfix) with ESMTP id E5B4C1600F1; Tue, 15 Sep 2020 18:50:54 -0700 (PDT) X-Virus-Scanned: amavisd-new at zimbra.cs.ucla.edu Original-Received: from zimbra.cs.ucla.edu ([127.0.0.1]) by localhost (zimbra.cs.ucla.edu [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id sUtAa8JBDtXA; Tue, 15 Sep 2020 18:50:54 -0700 (PDT) Original-Received: from day.example.com (cpe-75-82-69-226.socal.res.rr.com [75.82.69.226]) by zimbra.cs.ucla.edu (Postfix) with ESMTPSA id B6DD11600DE; Tue, 15 Sep 2020 18:50:54 -0700 (PDT) X-Mailer: git-send-email 2.17.1 Received-SPF: pass client-ip=131.179.128.68; envelope-from=eggert@cs.ucla.edu; helo=zimbra.cs.ucla.edu X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/15 21:50:57 X-ACL-Warn: Detected OS = Linux 3.1-3.10 [fuzzy] X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:188156 Archived-At: Improve doprnt performance, internal checking, and internal documentation. On my platform (Ubuntu 18.04.5 x86-64), this improved CPU speed of =E2=80=98make -C lisp compile-always=E2=80=99 by 6%= . This patch implements some of my suggestions in Bug#8545, with further changes suggested by Eli Zaretskii. * src/doprnt.c: Improve comments. (SIZE_BOUND_EXTRA): Now at top level, for parse_format_integer. (parse_format_integer): New static function, containing some of the old doprint. Fix a bug that caused doprnt to infloop on formats like "%10s" that Emacs does not use. We could simplify doprnt further if we dropped support for these never-used formats. (doprnt): Omit FORMAT_END argument, since it=E2=80=99s always NULL, which means doprnt must call strlen on FORMAT; doing this means doprnt needs just one pass over FORMAT, not two. All callers changed. Assume C99 to make code clearer. Do not use malloc or alloca to allocate a copy of the format FMTCPY; instead, use a small fixed-size array FMTSTAR, and use '*' in that array to represent width and precision, passing them as separate int arguments. Use eassume to pacify GCC in switch statements. Drop support for "%S" which is never used and which would cause GCC to warn anyway. * src/lisp.h (doprnt): Give it ATTRIBUTE_FORMAT_PRINTF (3, 0), since GCC can grok doprnt's new API. --- src/doprnt.c | 223 ++++++++++++++++++++++++++------------------------- src/lisp.h | 4 +- src/sysdep.c | 2 +- src/xdisp.c | 5 +- 4 files changed, 117 insertions(+), 117 deletions(-) diff --git a/src/doprnt.c b/src/doprnt.c index b0ba12552b..f154578c0d 100644 --- a/src/doprnt.c +++ b/src/doprnt.c @@ -28,6 +28,7 @@ . For %s and %c, when field width is specified (e.g., %25s), it accou= nts for the display width of each character, according to char-width-table.= That is, it does not assume that each character takes one column on disp= lay. + Nor does it assume that each character is a single byte. =20 . If the size of the buffer is not enough to produce the formatted st= ring in its entirety, it makes sure that truncation does not chop the last @@ -42,38 +43,41 @@ Emacs can handle. =20 OTOH, this function supports only a small subset of the standard C fo= rmatted - output facilities. E.g., %u and %ll are not supported, and precision= is - ignored %s and %c conversions. (See below for the detailed documenta= tion of - what is supported.) However, this is okay, as this function is suppo= sed to - be called from `error' and similar functions, and thus does not need = to - support features beyond those in `Fformat_message', which is used - by `error' on the Lisp level. */ + output facilities. E.g., %u is not supported, precision is ignored + in %s and %c conversions, and although %lld often works it is not + supported and code should use something like %"pM"d with intmax_t ins= tead. + (See below for the detailed documentation of what is supported.) + However, this is okay, as this function is supposed to be called + from 'error' and similar C functions, and thus does not need to + support all the features of 'Fformat_message', which is used by the + Lisp 'error' function. */ =20 /* In the FORMAT argument this function supports ` and ' as directives that output left and right quotes as per =E2=80=98text-quoting style=E2= =80=99. It also supports the following %-sequences: =20 %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 - or in decimal-point notation, whichever uses fewer characters. + 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. %% means produce a literal % character. =20 - A %-sequence may contain optional flag, width, and precision specifie= rs, and - a length modifier, as follows: + A %-sequence other than %% may contain optional flags, width, precisi= on, + and length, as follows: =20 %character =20 where flags is [+ -0], width is [0-9]+, precision is .[0-9]+, and len= gth is empty or l or the value of the pD or pI or PRIdMAX (sans "d") macr= os. - Also, %% in a format stands for a single % in the output. A % that - does not introduce a valid %-sequence causes undefined behavior. + A % that does not introduce a valid %-sequence causes undefined behav= ior. + ASCII bytes in FORMAT other than % are copied through as-is; + non-ASCII bytes should not appear in FORMAT. =20 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, @@ -99,7 +103,9 @@ =20 For %e, %f, and %g sequences, the number after the "." in the precisi= on specifier says how many decimal places to show; if zero, the decimal = point - itself is omitted. For %s and %S, the precision specifier is ignored= . */ + itself is omitted. For %d, %o, and %x sequences, the precision speci= fies + the minimum number of digits to appear. Precision specifiers are + not supported for other %-sequences. */ =20 #include #include @@ -115,9 +121,29 @@ another macro. */ #include "character.h" =20 -/* Generate output from a format-spec FORMAT, - terminated at position FORMAT_END. - (*FORMAT_END is not part of the format, but must exist and be readabl= e.) +/* Enough to handle floating point formats with large numbers. */ +enum { SIZE_BOUND_EXTRA =3D DBL_MAX_10_EXP + 50 }; + +/* Parse FMT as an unsigned decimal integer, putting its value into *VAL= UE. + Return the address of the first byte after the integer. + If FMT is not an integer, return FMT and store zero into *VALUE. */ +static char const * +parse_format_integer (char const *fmt, int *value) +{ + int n =3D 0; + bool overflow =3D false; + for (; '0' <=3D *fmt && *fmt <=3D '9'; fmt++) + { + overflow |=3D INT_MULTIPLY_WRAPV (n, 10, &n); + overflow |=3D INT_ADD_WRAPV (n, *fmt - '0', &n); + } + if (overflow || min (PTRDIFF_MAX, SIZE_MAX) - SIZE_BOUND_EXTRA < n) + error ("Format width or precision too large"); + *value =3D n; + return fmt; +} + +/* Generate output from a format-spec FORMAT. 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 @@ -128,15 +154,11 @@ Integers are passed as C integers. */ =20 ptrdiff_t -doprnt (char *buffer, ptrdiff_t bufsize, const char *format, - const char *format_end, va_list ap) +doprnt (char *buffer, ptrdiff_t bufsize, const char *format, va_list ap) { const char *fmt =3D format; /* Pointer into format string. */ char *bufptr =3D buffer; /* Pointer into output buffer. */ =20 - /* Enough to handle floating point formats with large numbers. */ - enum { SIZE_BOUND_EXTRA =3D DBL_MAX_10_EXP + 50 }; - /* Use this for sprintf unless we need something really big. */ char tembuf[SIZE_BOUND_EXTRA + 50]; =20 @@ -150,103 +172,91 @@ doprnt (char *buffer, ptrdiff_t bufsize, const cha= r *format, char *big_buffer =3D NULL; =20 enum text_quoting_style quoting_style =3D text_quoting_style (); - ptrdiff_t tem =3D -1; - char *string; - char fixed_buffer[20]; /* Default buffer for small formatting. */ - char *fmtcpy; - int minlen; - char charbuf[MAX_MULTIBYTE_LENGTH + 1]; /* Used for %c. */ - USE_SAFE_ALLOCA; - - if (format_end =3D=3D 0) - format_end =3D format + strlen (format); - - fmtcpy =3D (format_end - format < sizeof (fixed_buffer) - 1 - ? fixed_buffer - : SAFE_ALLOCA (format_end - format + 1)); =20 bufsize--; =20 /* Loop until end of format string or buffer full. */ - while (fmt < format_end && bufsize > 0) + while (*fmt && bufsize > 0) { char const *fmt0 =3D fmt; char fmtchar =3D *fmt++; if (fmtchar =3D=3D '%') { - ptrdiff_t size_bound =3D 0; ptrdiff_t width; /* Columns occupied by STRING on display. */ enum { pDlen =3D sizeof pD - 1, pIlen =3D sizeof pI - 1, - pMlen =3D sizeof PRIdMAX - 2 + pMlen =3D sizeof PRIdMAX - 2, + maxmlen =3D max (max (1, pDlen), max (pIlen, pMlen)) }; enum { no_modifier, long_modifier, pD_modifier, pI_modifier, pM_modifier } length_modifier =3D no_modifier; static char const modifier_len[] =3D { 0, 1, pDlen, pIlen, pMlen }; - int maxmlen =3D max (max (1, pDlen), max (pIlen, pMlen)); int mlen; + char charbuf[MAX_MULTIBYTE_LENGTH + 1]; /* Used for %c. */ =20 - /* Copy this one %-spec into fmtcpy. */ - string =3D fmtcpy; + /* Width and precision specified by this %-sequence. */ + int wid =3D 0, prec =3D -1; + + /* FMTSTAR will be a "%*.*X"-like version of this %-sequence. + Start by putting '%' into FMTSTAR. */ + char fmtstar[sizeof "%-+ 0*.*d" + maxmlen]; + char *string =3D fmtstar; *string++ =3D '%'; - while (fmt < format_end) + + /* Copy at most one instance of each flag into FMTSTAR. */ + bool minusflag =3D false, plusflag =3D false, zeroflag =3D false, + spaceflag =3D false; + for (;; fmt++) { - *string++ =3D *fmt; - if ('0' <=3D *fmt && *fmt <=3D '9') + *string =3D *fmt; + switch (*fmt) { - /* Get an idea of how much space we might need. - This might be a field width or a precision; e.g. - %1.1000f and %1000.1f both might need 1000+ bytes. - Parse the width or precision, checking for overflow. */ - int n =3D *fmt - '0'; - bool overflow =3D false; - while (fmt + 1 < format_end - && '0' <=3D fmt[1] && fmt[1] <=3D '9') - { - overflow |=3D INT_MULTIPLY_WRAPV (n, 10, &n); - overflow |=3D INT_ADD_WRAPV (n, fmt[1] - '0', &n); - *string++ =3D *++fmt; - } - - if (overflow - || min (PTRDIFF_MAX, SIZE_MAX) - SIZE_BOUND_EXTRA < n) - error ("Format width or precision too large"); - if (size_bound < n) - size_bound =3D n; + case '-': string +=3D !minusflag; minusflag =3D true; continue; + case '+': string +=3D !plusflag; plusflag =3D true; continue; + case ' ': string +=3D !spaceflag; spaceflag =3D true; continue; + case '0': string +=3D !zeroflag; zeroflag =3D true; continue; } - else if (! (*fmt =3D=3D '-' || *fmt =3D=3D ' ' || *fmt =3D=3D '.' - || *fmt =3D=3D '+')) - break; - fmt++; + break; } =20 + /* Parse width and precision, putting "*.*" into FMTSTAR. */ + if ('1' <=3D *fmt && *fmt <=3D '9') + fmt =3D parse_format_integer (fmt, &wid); + if (*fmt =3D=3D '.') + fmt =3D parse_format_integer (fmt + 1, &prec); + *string++ =3D '*'; + *string++ =3D '.'; + *string++ =3D '*'; + /* Check for the length modifiers in textual length order, so that longer modifiers override shorter ones. */ for (mlen =3D 1; mlen <=3D maxmlen; mlen++) { - if (format_end - fmt < mlen) - break; if (mlen =3D=3D 1 && *fmt =3D=3D 'l') length_modifier =3D long_modifier; - if (mlen =3D=3D pDlen && memcmp (fmt, pD, pDlen) =3D=3D 0) + if (mlen =3D=3D pDlen && strncmp (fmt, pD, pDlen) =3D=3D 0) length_modifier =3D pD_modifier; - if (mlen =3D=3D pIlen && memcmp (fmt, pI, pIlen) =3D=3D 0) + if (mlen =3D=3D pIlen && strncmp (fmt, pI, pIlen) =3D=3D 0) length_modifier =3D pI_modifier; - if (mlen =3D=3D pMlen && memcmp (fmt, PRIdMAX, pMlen) =3D=3D 0) + if (mlen =3D=3D pMlen && strncmp (fmt, PRIdMAX, pMlen) =3D=3D 0) length_modifier =3D pM_modifier; } =20 + /* Copy optional length modifier and conversion specifier + character into FMTSTAR, and append a NUL. */ mlen =3D modifier_len[length_modifier]; - memcpy (string, fmt + 1, mlen); - string +=3D mlen; + string =3D mempcpy (string, fmt, mlen + 1); fmt +=3D mlen; *string =3D 0; =20 - /* Make the size bound large enough to handle floating point formats + /* An idea of how much space we might need. + This might be a field width or a precision; e.g. + %1.1000f and %1000.1f both might need 1000+ bytes. + Make it large enough to handle floating point formats with large numbers. */ - size_bound +=3D SIZE_BOUND_EXTRA; + ptrdiff_t size_bound =3D max (wid, prec) + SIZE_BOUND_EXTRA; =20 /* Make sure we have that much. */ if (size_bound > size_allocated) @@ -257,48 +267,49 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char= *format, sprintf_buffer =3D big_buffer; size_allocated =3D size_bound; } - minlen =3D 0; + int minlen =3D 0; + ptrdiff_t tem; switch (*fmt++) { default: - error ("Invalid format operation %s", fmtcpy); + error ("Invalid format operation %s", fmt0); =20 -/* case 'b': */ - case 'l': case 'd': switch (length_modifier) { case no_modifier: { int v =3D va_arg (ap, int); - tem =3D sprintf (sprintf_buffer, fmtcpy, v); + tem =3D sprintf (sprintf_buffer, fmtstar, wid, prec, v); } break; case long_modifier: { long v =3D va_arg (ap, long); - tem =3D sprintf (sprintf_buffer, fmtcpy, v); + tem =3D sprintf (sprintf_buffer, fmtstar, wid, prec, v); } break; case pD_modifier: signed_pD_modifier: { ptrdiff_t v =3D va_arg (ap, ptrdiff_t); - tem =3D sprintf (sprintf_buffer, fmtcpy, v); + tem =3D sprintf (sprintf_buffer, fmtstar, wid, prec, v); } break; case pI_modifier: { EMACS_INT v =3D va_arg (ap, EMACS_INT); - tem =3D sprintf (sprintf_buffer, fmtcpy, v); + tem =3D sprintf (sprintf_buffer, fmtstar, wid, prec, v); } break; case pM_modifier: { intmax_t v =3D va_arg (ap, intmax_t); - tem =3D sprintf (sprintf_buffer, fmtcpy, v); + tem =3D sprintf (sprintf_buffer, fmtstar, wid, prec, v); } break; + default: + eassume (false); } /* Now copy into final output, truncating as necessary. */ string =3D sprintf_buffer; @@ -311,13 +322,13 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char= *format, case no_modifier: { unsigned v =3D va_arg (ap, unsigned); - tem =3D sprintf (sprintf_buffer, fmtcpy, v); + tem =3D sprintf (sprintf_buffer, fmtstar, wid, prec, v); } break; case long_modifier: { unsigned long v =3D va_arg (ap, unsigned long); - tem =3D sprintf (sprintf_buffer, fmtcpy, v); + tem =3D sprintf (sprintf_buffer, fmtstar, wid, prec, v); } break; case pD_modifier: @@ -325,15 +336,17 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char= *format, case pI_modifier: { EMACS_UINT v =3D va_arg (ap, EMACS_UINT); - tem =3D sprintf (sprintf_buffer, fmtcpy, v); + tem =3D sprintf (sprintf_buffer, fmtstar, wid, prec, v); } break; case pM_modifier: { uintmax_t v =3D va_arg (ap, uintmax_t); - tem =3D sprintf (sprintf_buffer, fmtcpy, v); + tem =3D sprintf (sprintf_buffer, fmtstar, wid, prec, v); } break; + default: + eassume (false); } /* Now copy into final output, truncating as necessary. */ string =3D sprintf_buffer; @@ -344,22 +357,18 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char= *format, case 'g': { double d =3D va_arg (ap, double); - tem =3D sprintf (sprintf_buffer, fmtcpy, d); + tem =3D sprintf (sprintf_buffer, fmtstar, wid, prec, d); /* Now copy into final output, truncating as necessary. */ string =3D sprintf_buffer; goto doit; } =20 - case 'S': - string[-1] =3D 's'; - FALLTHROUGH; case 's': - if (fmtcpy[1] !=3D 's') - minlen =3D atoi (&fmtcpy[1]); + minlen =3D minusflag ? -wid : wid; string =3D va_arg (ap, char *); tem =3D strnlen (string, STRING_BYTES_BOUND + 1); if (tem =3D=3D STRING_BYTES_BOUND + 1) - error ("String for %%s or %%S format is too long"); + error ("String for %%s format is too long"); width =3D strwidth (string, tem); goto doit1; =20 @@ -432,14 +441,12 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char= *format, string =3D charbuf; string[tem] =3D 0; width =3D strwidth (string, tem); - if (fmtcpy[1] !=3D 'c') - minlen =3D atoi (&fmtcpy[1]); + minlen =3D minusflag ? -wid : wid; goto doit1; } =20 case '%': /* Treat this '%' as normal. */ - fmt0 =3D fmt - 1; break; } } @@ -450,13 +457,13 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char= *format, src =3D uLSQM, srclen =3D sizeof uLSQM - 1; else if (quoting_style =3D=3D CURVE_QUOTING_STYLE && fmtchar =3D=3D= '\'') src =3D uRSQM, srclen =3D sizeof uRSQM - 1; - else if (quoting_style =3D=3D STRAIGHT_QUOTING_STYLE && fmtchar =3D= =3D '`') - src =3D "'", srclen =3D 1; else { - while (fmt < format_end && !CHAR_HEAD_P (*fmt)) - fmt++; - src =3D fmt0, srclen =3D fmt - fmt0; + if (quoting_style =3D=3D STRAIGHT_QUOTING_STYLE && fmtchar =3D=3D '`'= ) + fmtchar =3D '\''; + eassert (ASCII_CHAR_P (fmtchar)); + *bufptr++ =3D fmtchar; + continue; } =20 if (bufsize < srclen) @@ -479,8 +486,6 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char *= format, xfree (big_buffer); =20 *bufptr =3D 0; /* Make sure our string ends with a '\0' */ - - SAFE_FREE (); return bufptr - buffer; } =20 @@ -495,10 +500,9 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char = *format, ptrdiff_t esprintf (char *buf, char const *format, ...) { - ptrdiff_t nbytes; va_list ap; va_start (ap, format); - nbytes =3D doprnt (buf, TYPE_MAXIMUM (ptrdiff_t), format, 0, ap); + ptrdiff_t nbytes =3D doprnt (buf, TYPE_MAXIMUM (ptrdiff_t), format, ap= ); va_end (ap); return nbytes; } @@ -534,10 +538,9 @@ evxprintf (char **buf, ptrdiff_t *bufsize, { for (;;) { - ptrdiff_t nbytes; va_list ap_copy; va_copy (ap_copy, ap); - nbytes =3D doprnt (*buf, *bufsize, format, 0, ap_copy); + ptrdiff_t nbytes =3D doprnt (*buf, *bufsize, format, ap_copy); va_end (ap_copy); if (nbytes < *bufsize - 1) return nbytes; diff --git a/src/lisp.h b/src/lisp.h index a24898004d..957ca41702 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -4034,8 +4034,8 @@ #define FLOAT_TO_STRING_BUFSIZE 350 extern void syms_of_print (void); =20 /* Defined in doprnt.c. */ -extern ptrdiff_t doprnt (char *, ptrdiff_t, const char *, const char *, - va_list); +extern ptrdiff_t doprnt (char *, ptrdiff_t, const char *, va_list) + ATTRIBUTE_FORMAT_PRINTF (3, 0); extern ptrdiff_t esprintf (char *, char const *, ...) ATTRIBUTE_FORMAT_PRINTF (2, 3); extern ptrdiff_t exprintf (char **, ptrdiff_t *, char const *, ptrdiff_t= , diff --git a/src/sysdep.c b/src/sysdep.c index e161172a79..790ae084d3 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -2192,7 +2192,7 @@ snprintf (char *buf, size_t bufsize, char const *fo= rmat, ...) if (size) { va_start (ap, format); - nbytes =3D doprnt (buf, size, format, 0, ap); + nbytes =3D doprnt (buf, size, format, ap); va_end (ap); } =20 diff --git a/src/xdisp.c b/src/xdisp.c index 615f0ca7cf..213c2a464a 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -11269,13 +11269,10 @@ vmessage (const char *m, va_list ap) { if (m) { - ptrdiff_t len; ptrdiff_t maxsize =3D FRAME_MESSAGE_BUF_SIZE (f); USE_SAFE_ALLOCA; char *message_buf =3D SAFE_ALLOCA (maxsize + 1); - - len =3D doprnt (message_buf, maxsize, m, 0, ap); - + ptrdiff_t len =3D doprnt (message_buf, maxsize, m, ap); message3 (make_string (message_buf, len)); SAFE_FREE (); } --=20 2.17.1