summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Zaretskii <eliz@gnu.org>2011-04-25 11:04:22 +0300
committerEli Zaretskii <eliz@gnu.org>2011-04-25 11:04:22 +0300
commit825cd63ca98121d602b4a8dcffa55d29841224a0 (patch)
tree0ecfbd1149dd944fb7b77132ef8ef0c6201d9180
parente2822bd2ea32c577342b9618a301f8661551f7a3 (diff)
downloademacs-825cd63ca98121d602b4a8dcffa55d29841224a0.tar.gz
Improve doprnt and its use in verror. (Bug#8545)
src/doprnt.c (doprnt): Document the set of format control sequences supported by the function. Use SAFE_ALLOCA instead of always using `alloca'. src/eval.c (verror): Don't limit the buffer size at size_max-1, that is one byte too soon. Don't use xrealloc; instead xfree and xmalloc anew.
-rw-r--r--src/ChangeLog11
-rw-r--r--src/doprnt.c62
-rw-r--r--src/eval.c11
3 files changed, 70 insertions, 14 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 410a3b15ffb..cd03d1fa186 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,14 @@
+2011-04-25 Eli Zaretskii <eliz@gnu.org>
+
+ Improve doprnt and its use in verror. (Bug#8545)
+ * doprnt.c (doprnt): Document the set of format control sequences
+ supported by the function. Use SAFE_ALLOCA instead of always
+ using `alloca'.
+
+ * eval.c (verror): Don't limit the buffer size at size_max-1, that
+ is one byte too soon. Don't use xrealloc; instead xfree and
+ xmalloc anew.
+
2011-04-24 Teodor Zlatanov <tzz@lifelogs.com>
* gnutls.h: Add GNUTLS_STAGE_CALLBACKS enum to denote we're in the
diff --git a/src/doprnt.c b/src/doprnt.c
index f124db13221..3ac1d9963a9 100644
--- a/src/doprnt.c
+++ b/src/doprnt.c
@@ -43,10 +43,54 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
OTOH, this function supports only a small subset of the standard C formatted
output facilities. E.g., %u and %ll are not supported, and precision is
- largely ignored except for converting floating-point values. However, this
- is okay, as this function is supposed to be called from `error' and similar
- functions, and thus does not need to support features beyond those in
- `Fformat', which is used by `error' on the Lisp level. */
+ ignored %s and %c conversions. (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 functions, and thus does not need to
+ support features beyond those in `Fformat', which is used by `error' on the
+ Lisp level. */
+
+/* This function supports the following %-sequences in the `format'
+ argument:
+
+ %s means print a string argument.
+ %S is silently treated as %s, for loose compatibility with `Fformat'.
+ %d means print a `signed int' argument in decimal.
+ %l means print a `long 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.
+ %c means print a `signed int' argument as a single character.
+ %% means produce a literal % character.
+
+ A %-sequence may contain optional flag, width, and precision specifiers, as
+ follows:
+
+ %<flags><width><precision>character
+
+ where flags is [+ -0l], width is [0-9]+, and precision is .[0-9]+
+
+ The + flag character inserts a + before any positive number, while a space
+ inserts a space before any positive number; these flags only affect %d, %l,
+ %o, %x, %e, %f, and %g sequences. The - and 0 flags affect the width
+ specifier, as described below.
+
+ The l (lower-case letter ell) flag is a `long' data type modifier: it is
+ supported for %d, %o, and %x conversions of integral arguments, and means
+ that the respective argument is to be treated as `long int' or `unsigned
+ long int'. The EMACS_INT data type should use this modifier.
+
+ 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
+ on the right if the - flag is present. The padding character is normally a
+ space, but (for numerical arguments only) it is 0 if the 0 flag is present.
+ The - flag takes precedence over the 0 flag.
+
+ For %e, %f, and %g sequences, the number after the "." in the precision
+ 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. */
#include <config.h>
#include <stdio.h>
@@ -79,9 +123,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
terminated at position FORMAT_END.
Output goes in BUFFER, which has room for BUFSIZE chars.
If the output does not fit, truncate it to fit.
- Returns the number of bytes stored into BUFFER.
- ARGS points to the vector of arguments, and NARGS says how many.
- A double counts as two arguments.
+ Returns 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. */
@@ -110,6 +153,7 @@ doprnt (char *buffer, register size_t bufsize, const char *format,
char *fmtcpy;
int minlen;
char charbuf[MAX_MULTIBYTE_LENGTH + 1]; /* Used for %c. */
+ USE_SAFE_ALLOCA;
if (format_end == 0)
format_end = format + strlen (format);
@@ -117,7 +161,7 @@ doprnt (char *buffer, register size_t bufsize, const char *format,
if ((format_end - format + 1) < sizeof (fixed_buffer))
fmtcpy = fixed_buffer;
else
- fmtcpy = (char *) alloca (format_end - format + 1);
+ SAFE_ALLOCA (fmtcpy, char *, format_end - format + 1);
bufsize--;
@@ -342,5 +386,7 @@ doprnt (char *buffer, register size_t bufsize, const char *format,
xfree (big_buffer);
*bufptr = 0; /* Make sure our string ends with a '\0' */
+
+ SAFE_FREE ();
return bufptr - buffer;
}
diff --git a/src/eval.c b/src/eval.c
index c3676720940..d1f327021e6 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -2012,15 +2012,14 @@ verror (const char *m, va_list ap)
break;
if (size <= size_max / 2)
size *= 2;
- else if (size < size_max - 1)
- size = size_max - 1;
+ else if (size < size_max)
+ size = size_max;
else
break; /* and leave the message truncated */
- if (buffer == buf)
- buffer = (char *) xmalloc (size);
- else
- buffer = (char *) xrealloc (buffer, size);
+ if (buffer != buf)
+ xfree (buffer);
+ buffer = (char *) xmalloc (size);
}
string = make_string (buffer, used);