aboutsummaryrefslogtreecommitdiffstats
path: root/src/doprnt.c
diff options
context:
space:
mode:
authorStefan Monnier2012-03-25 16:37:21 -0400
committerStefan Monnier2012-03-25 16:37:21 -0400
commit699c782b7668c44d0fa4446331b0590a6d5dac82 (patch)
tree5dcce364741d0761920a3d274b0fc8aba4103d45 /src/doprnt.c
parent98fb480ee31bf74cf554044f60f21df16566dd7f (diff)
parente99a9b8bdccadded1f6fae88ee7a2a93dfd4eacf (diff)
downloademacs-pending.tar.gz
emacs-pending.zip
Merge from trunkpending
Diffstat (limited to 'src/doprnt.c')
-rw-r--r--src/doprnt.c238
1 files changed, 168 insertions, 70 deletions
diff --git a/src/doprnt.c b/src/doprnt.c
index 195598c07ea..b8eb0f07199 100644
--- a/src/doprnt.c
+++ b/src/doprnt.c
@@ -1,7 +1,7 @@
1/* Output like sprintf to a buffer of specified size. 1/* Output like sprintf to a buffer of specified size.
2 Also takes args differently: pass one pointer to the end 2 Also takes args differently: pass one pointer to the end
3 of the format string in addition to the format string itself. 3 of the format string in addition to the format string itself.
4 Copyright (C) 1985, 2001-2011 Free Software Foundation, Inc. 4 Copyright (C) 1985, 2001-2012 Free Software Foundation, Inc.
5 5
6This file is part of GNU Emacs. 6This file is part of GNU Emacs.
7 7
@@ -26,7 +26,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
26 of the (`int') argument, suitable for display in an Emacs buffer. 26 of the (`int') argument, suitable for display in an Emacs buffer.
27 27
28 . For %s and %c, when field width is specified (e.g., %25s), it accounts for 28 . For %s and %c, when field width is specified (e.g., %25s), it accounts for
29 the diplay width of each character, according to char-width-table. That 29 the display width of each character, according to char-width-table. That
30 is, it does not assume that each character takes one column on display. 30 is, it does not assume that each character takes one column on display.
31 31
32 . If the size of the buffer is not enough to produce the formatted string in 32 . If the size of the buffer is not enough to produce the formatted string in
@@ -70,9 +70,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
70 %<flags><width><precision><length>character 70 %<flags><width><precision><length>character
71 71
72 where flags is [+ -0], width is [0-9]+, precision is .[0-9]+, and length 72 where flags is [+ -0], width is [0-9]+, precision is .[0-9]+, and length
73 is empty or l or the value of the pI macro. Also, %% in a format 73 is empty or l or the value of the pD or pI or pMd (sans "d") macros.
74 stands for a single % in the output. A % that does not introduce a 74 Also, %% in a format stands for a single % in the output. A % that
75 valid %-sequence causes undefined behavior. 75 does not introduce a valid %-sequence causes undefined behavior.
76 76
77 The + flag character inserts a + before any positive number, while a space 77 The + flag character inserts a + before any positive number, while a space
78 inserts a space before any positive number; these flags only affect %d, %o, 78 inserts a space before any positive number; these flags only affect %d, %o,
@@ -85,8 +85,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
85 modifier: it is supported for %d, %o, and %x conversions of integral 85 modifier: it is supported for %d, %o, and %x conversions of integral
86 arguments, must immediately precede the conversion specifier, and means that 86 arguments, must immediately precede the conversion specifier, and means that
87 the respective argument is to be treated as `long int' or `unsigned long 87 the respective argument is to be treated as `long int' or `unsigned long
88 int'. Similarly, the value of the pI macro means to use EMACS_INT or 88 int'. Similarly, the value of the pD macro means to use ptrdiff_t,
89 EMACS_UINT and the empty length modifier means `int' or `unsigned int'. 89 the value of the pI macro means to use EMACS_INT or EMACS_UINT, the
90 value of the pMd etc. macros means to use intmax_t or uintmax_t,
91 and the empty length modifier means `int' or `unsigned int'.
90 92
91 The width specifier supplies a lower limit for the length of the printed 93 The width specifier supplies a lower limit for the length of the printed
92 representation. The padding, if any, normally goes on the left, but it goes 94 representation. The padding, if any, normally goes on the left, but it goes
@@ -102,13 +104,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
102#include <stdio.h> 104#include <stdio.h>
103#include <ctype.h> 105#include <ctype.h>
104#include <setjmp.h> 106#include <setjmp.h>
105
106#ifdef STDC_HEADERS
107#include <float.h> 107#include <float.h>
108#endif
109
110#include <unistd.h> 108#include <unistd.h>
111
112#include <limits.h> 109#include <limits.h>
113 110
114#include "lisp.h" 111#include "lisp.h"
@@ -134,8 +131,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
134 String arguments are passed as C strings. 131 String arguments are passed as C strings.
135 Integers are passed as C integers. */ 132 Integers are passed as C integers. */
136 133
137size_t 134ptrdiff_t
138doprnt (char *buffer, register size_t bufsize, const char *format, 135doprnt (char *buffer, ptrdiff_t bufsize, const char *format,
139 const char *format_end, va_list ap) 136 const char *format_end, va_list ap)
140{ 137{
141 const char *fmt = format; /* Pointer into format string */ 138 const char *fmt = format; /* Pointer into format string */
@@ -145,7 +142,7 @@ doprnt (char *buffer, register size_t bufsize, const char *format,
145 char tembuf[DBL_MAX_10_EXP + 100]; 142 char tembuf[DBL_MAX_10_EXP + 100];
146 143
147 /* Size of sprintf_buffer. */ 144 /* Size of sprintf_buffer. */
148 size_t size_allocated = sizeof (tembuf); 145 ptrdiff_t size_allocated = sizeof (tembuf);
149 146
150 /* Buffer to use for sprintf. Either tembuf or same as BIG_BUFFER. */ 147 /* Buffer to use for sprintf. Either tembuf or same as BIG_BUFFER. */
151 char *sprintf_buffer = tembuf; 148 char *sprintf_buffer = tembuf;
@@ -164,7 +161,7 @@ doprnt (char *buffer, register size_t bufsize, const char *format,
164 if (format_end == 0) 161 if (format_end == 0)
165 format_end = format + strlen (format); 162 format_end = format + strlen (format);
166 163
167 if ((format_end - format + 1) < sizeof (fixed_buffer)) 164 if (format_end - format < sizeof (fixed_buffer) - 1)
168 fmtcpy = fixed_buffer; 165 fmtcpy = fixed_buffer;
169 else 166 else
170 SAFE_ALLOCA (fmtcpy, char *, format_end - format + 1); 167 SAFE_ALLOCA (fmtcpy, char *, format_end - format + 1);
@@ -176,10 +173,19 @@ doprnt (char *buffer, register size_t bufsize, const char *format,
176 { 173 {
177 if (*fmt == '%') /* Check for a '%' character */ 174 if (*fmt == '%') /* Check for a '%' character */
178 { 175 {
179 size_t size_bound = 0; 176 ptrdiff_t size_bound = 0;
180 EMACS_INT width; /* Columns occupied by STRING on display. */ 177 EMACS_INT width; /* Columns occupied by STRING on display. */
181 int long_flag = 0; 178 enum {
182 int pIlen = sizeof pI - 1; 179 pDlen = sizeof pD - 1,
180 pIlen = sizeof pI - 1,
181 pMlen = sizeof pMd - 2
182 };
183 enum {
184 no_modifier, long_modifier, pD_modifier, pI_modifier, pM_modifier
185 } length_modifier = no_modifier;
186 static char const modifier_len[] = { 0, 1, pDlen, pIlen, pMlen };
187 int maxmlen = max (max (1, pDlen), max (pIlen, pMlen));
188 int mlen;
183 189
184 fmt++; 190 fmt++;
185 /* Copy this one %-spec into fmtcpy. */ 191 /* Copy this one %-spec into fmtcpy. */
@@ -194,16 +200,16 @@ doprnt (char *buffer, register size_t bufsize, const char *format,
194 This might be a field width or a precision; e.g. 200 This might be a field width or a precision; e.g.
195 %1.1000f and %1000.1f both might need 1000+ bytes. 201 %1.1000f and %1000.1f both might need 1000+ bytes.
196 Parse the width or precision, checking for overflow. */ 202 Parse the width or precision, checking for overflow. */
197 size_t n = *fmt - '0'; 203 ptrdiff_t n = *fmt - '0';
198 while (fmt + 1 < format_end 204 while (fmt + 1 < format_end
199 && '0' <= fmt[1] && fmt[1] <= '9') 205 && '0' <= fmt[1] && fmt[1] <= '9')
200 { 206 {
201 /* Avoid size_t overflow. Avoid int overflow too, as 207 /* Avoid ptrdiff_t, size_t, and int overflow, as
202 many sprintfs mishandle widths greater than INT_MAX. 208 many sprintfs mishandle widths greater than INT_MAX.
203 This test is simple but slightly conservative: e.g., 209 This test is simple but slightly conservative: e.g.,
204 (INT_MAX - INT_MAX % 10) is reported as an overflow 210 (INT_MAX - INT_MAX % 10) is reported as an overflow
205 even when it's not. */ 211 even when it's not. */
206 if (n >= min (INT_MAX, SIZE_MAX) / 10) 212 if (n >= min (INT_MAX, min (PTRDIFF_MAX, SIZE_MAX)) / 10)
207 error ("Format width or precision too large"); 213 error ("Format width or precision too large");
208 n = n * 10 + fmt[1] - '0'; 214 n = n * 10 + fmt[1] - '0';
209 *string++ = *++fmt; 215 *string++ = *++fmt;
@@ -218,24 +224,31 @@ doprnt (char *buffer, register size_t bufsize, const char *format,
218 fmt++; 224 fmt++;
219 } 225 }
220 226
221 if (0 < pIlen && pIlen <= format_end - fmt 227 /* Check for the length modifiers in textual length order, so
222 && memcmp (fmt, pI, pIlen) == 0) 228 that longer modifiers override shorter ones. */
223 { 229 for (mlen = 1; mlen <= maxmlen; mlen++)
224 long_flag = 2;
225 memcpy (string, fmt + 1, pIlen);
226 string += pIlen;
227 fmt += pIlen;
228 }
229 else if (fmt < format_end && *fmt == 'l')
230 { 230 {
231 long_flag = 1; 231 if (format_end - fmt < mlen)
232 *string++ = *++fmt; 232 break;
233 if (mlen == 1 && *fmt == 'l')
234 length_modifier = long_modifier;
235 if (mlen == pDlen && memcmp (fmt, pD, pDlen) == 0)
236 length_modifier = pD_modifier;
237 if (mlen == pIlen && memcmp (fmt, pI, pIlen) == 0)
238 length_modifier = pI_modifier;
239 if (mlen == pMlen && memcmp (fmt, pMd, pMlen) == 0)
240 length_modifier = pM_modifier;
233 } 241 }
242
243 mlen = modifier_len[length_modifier];
244 memcpy (string, fmt + 1, mlen);
245 string += mlen;
246 fmt += mlen;
234 *string = 0; 247 *string = 0;
235 248
236 /* Make the size bound large enough to handle floating point formats 249 /* Make the size bound large enough to handle floating point formats
237 with large numbers. */ 250 with large numbers. */
238 if (size_bound > SIZE_MAX - DBL_MAX_10_EXP - 50) 251 if (size_bound > min (PTRDIFF_MAX, SIZE_MAX) - DBL_MAX_10_EXP - 50)
239 error ("Format width or precision too large"); 252 error ("Format width or precision too large");
240 size_bound += DBL_MAX_10_EXP + 50; 253 size_bound += DBL_MAX_10_EXP + 50;
241 254
@@ -257,61 +270,84 @@ doprnt (char *buffer, register size_t bufsize, const char *format,
257/* case 'b': */ 270/* case 'b': */
258 case 'l': 271 case 'l':
259 case 'd': 272 case 'd':
260 { 273 switch (length_modifier)
261 int i; 274 {
262 long l; 275 case no_modifier:
263
264 if (1 < long_flag)
265 { 276 {
266 EMACS_INT ll = va_arg (ap, EMACS_INT); 277 int v = va_arg (ap, int);
267 sprintf (sprintf_buffer, fmtcpy, ll); 278 sprintf (sprintf_buffer, fmtcpy, v);
268 } 279 }
269 else if (long_flag) 280 break;
281 case long_modifier:
270 { 282 {
271 l = va_arg(ap, long); 283 long v = va_arg (ap, long);
272 sprintf (sprintf_buffer, fmtcpy, l); 284 sprintf (sprintf_buffer, fmtcpy, v);
273 } 285 }
274 else 286 break;
287 case pD_modifier:
288 signed_pD_modifier:
275 { 289 {
276 i = va_arg(ap, int); 290 ptrdiff_t v = va_arg (ap, ptrdiff_t);
277 sprintf (sprintf_buffer, fmtcpy, i); 291 sprintf (sprintf_buffer, fmtcpy, v);
278 } 292 }
279 /* Now copy into final output, truncating as necessary. */ 293 break;
280 string = sprintf_buffer; 294 case pI_modifier:
281 goto doit; 295 {
282 } 296 EMACS_INT v = va_arg (ap, EMACS_INT);
297 sprintf (sprintf_buffer, fmtcpy, v);
298 }
299 break;
300 case pM_modifier:
301 {
302 intmax_t v = va_arg (ap, intmax_t);
303 sprintf (sprintf_buffer, fmtcpy, v);
304 }
305 break;
306 }
307 /* Now copy into final output, truncating as necessary. */
308 string = sprintf_buffer;
309 goto doit;
283 310
284 case 'o': 311 case 'o':
285 case 'x': 312 case 'x':
286 { 313 switch (length_modifier)
287 unsigned u; 314 {
288 unsigned long ul; 315 case no_modifier:
289
290 if (1 < long_flag)
291 { 316 {
292 EMACS_UINT ull = va_arg (ap, EMACS_UINT); 317 unsigned v = va_arg (ap, unsigned);
293 sprintf (sprintf_buffer, fmtcpy, ull); 318 sprintf (sprintf_buffer, fmtcpy, v);
294 } 319 }
295 else if (long_flag) 320 break;
321 case long_modifier:
296 { 322 {
297 ul = va_arg(ap, unsigned long); 323 unsigned long v = va_arg (ap, unsigned long);
298 sprintf (sprintf_buffer, fmtcpy, ul); 324 sprintf (sprintf_buffer, fmtcpy, v);
299 } 325 }
300 else 326 break;
327 case pD_modifier:
328 goto signed_pD_modifier;
329 case pI_modifier:
301 { 330 {
302 u = va_arg(ap, unsigned); 331 EMACS_UINT v = va_arg (ap, EMACS_UINT);
303 sprintf (sprintf_buffer, fmtcpy, u); 332 sprintf (sprintf_buffer, fmtcpy, v);
304 } 333 }
305 /* Now copy into final output, truncating as necessary. */ 334 break;
306 string = sprintf_buffer; 335 case pM_modifier:
307 goto doit; 336 {
308 } 337 uintmax_t v = va_arg (ap, uintmax_t);
338 sprintf (sprintf_buffer, fmtcpy, v);
339 }
340 break;
341 }
342 /* Now copy into final output, truncating as necessary. */
343 string = sprintf_buffer;
344 goto doit;
309 345
310 case 'f': 346 case 'f':
311 case 'e': 347 case 'e':
312 case 'g': 348 case 'g':
313 { 349 {
314 double d = va_arg(ap, double); 350 double d = va_arg (ap, double);
315 sprintf (sprintf_buffer, fmtcpy, d); 351 sprintf (sprintf_buffer, fmtcpy, d);
316 /* Now copy into final output, truncating as necessary. */ 352 /* Now copy into final output, truncating as necessary. */
317 string = sprintf_buffer; 353 string = sprintf_buffer;
@@ -391,7 +427,7 @@ doprnt (char *buffer, register size_t bufsize, const char *format,
391 427
392 case 'c': 428 case 'c':
393 { 429 {
394 int chr = va_arg(ap, int); 430 int chr = va_arg (ap, int);
395 tem = CHAR_STRING (chr, (unsigned char *) charbuf); 431 tem = CHAR_STRING (chr, (unsigned char *) charbuf);
396 string = charbuf; 432 string = charbuf;
397 string[tem] = 0; 433 string[tem] = 0;
@@ -431,3 +467,65 @@ doprnt (char *buffer, register size_t bufsize, const char *format,
431 SAFE_FREE (); 467 SAFE_FREE ();
432 return bufptr - buffer; 468 return bufptr - buffer;
433} 469}
470
471/* Format to an unbounded buffer BUF. This is like sprintf, except it
472 is not limited to returning an 'int' so it doesn't have a silly 2
473 GiB limit on typical 64-bit hosts. However, it is limited to the
474 Emacs-style formats that doprnt supports.
475
476 Return the number of bytes put into BUF, excluding the terminating
477 '\0'. */
478ptrdiff_t
479esprintf (char *buf, char const *format, ...)
480{
481 ptrdiff_t nbytes;
482 va_list ap;
483 va_start (ap, format);
484 nbytes = doprnt (buf, TYPE_MAXIMUM (ptrdiff_t), format, 0, ap);
485 va_end (ap);
486 return nbytes;
487}
488
489#if defined HAVE_X_WINDOWS && defined USE_X_TOOLKIT
490
491/* Format to buffer *BUF of positive size *BUFSIZE, reallocating *BUF
492 and updating *BUFSIZE if the buffer is too small, and otherwise
493 behaving line esprintf. When reallocating, free *BUF unless it is
494 equal to NONHEAPBUF, and if BUFSIZE_MAX is nonnegative then signal
495 memory exhaustion instead of growing the buffer size past
496 BUFSIZE_MAX. */
497ptrdiff_t
498exprintf (char **buf, ptrdiff_t *bufsize,
499 char const *nonheapbuf, ptrdiff_t bufsize_max,
500 char const *format, ...)
501{
502 ptrdiff_t nbytes;
503 va_list ap;
504 va_start (ap, format);
505 nbytes = evxprintf (buf, bufsize, nonheapbuf, bufsize_max, format, ap);
506 va_end (ap);
507 return nbytes;
508}
509
510#endif
511
512/* Act like exprintf, except take a va_list. */
513ptrdiff_t
514evxprintf (char **buf, ptrdiff_t *bufsize,
515 char const *nonheapbuf, ptrdiff_t bufsize_max,
516 char const *format, va_list ap)
517{
518 for (;;)
519 {
520 ptrdiff_t nbytes;
521 va_list ap_copy;
522 va_copy (ap_copy, ap);
523 nbytes = doprnt (*buf, *bufsize, format, 0, ap_copy);
524 va_end (ap_copy);
525 if (nbytes < *bufsize - 1)
526 return nbytes;
527 if (*buf != nonheapbuf)
528 xfree (*buf);
529 *buf = xpalloc (NULL, bufsize, 1, bufsize_max, 1);
530 }
531}