diff options
Diffstat (limited to 'src/doprnt.c')
| -rw-r--r-- | src/doprnt.c | 238 |
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 | ||
| 6 | This file is part of GNU Emacs. | 6 | This 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 | ||
| 137 | size_t | 134 | ptrdiff_t |
| 138 | doprnt (char *buffer, register size_t bufsize, const char *format, | 135 | doprnt (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'. */ | ||
| 478 | ptrdiff_t | ||
| 479 | esprintf (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. */ | ||
| 497 | ptrdiff_t | ||
| 498 | exprintf (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. */ | ||
| 513 | ptrdiff_t | ||
| 514 | evxprintf (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 | } | ||