aboutsummaryrefslogtreecommitdiffstats
path: root/src/doprnt.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/doprnt.c')
-rw-r--r--src/doprnt.c106
1 files changed, 72 insertions, 34 deletions
diff --git a/src/doprnt.c b/src/doprnt.c
index 36eb272caae..f182529b801 100644
--- a/src/doprnt.c
+++ b/src/doprnt.c
@@ -30,6 +30,11 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
30 30
31#include <unistd.h> 31#include <unistd.h>
32 32
33#include <limits.h>
34#ifndef SIZE_MAX
35# define SIZE_MAX ((size_t) -1)
36#endif
37
33#include "lisp.h" 38#include "lisp.h"
34 39
35/* Since we use the macro CHAR_HEAD_P, we have to include this, but 40/* Since we use the macro CHAR_HEAD_P, we have to include this, but
@@ -51,8 +56,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
51 String arguments are passed as C strings. 56 String arguments are passed as C strings.
52 Integers are passed as C integers. */ 57 Integers are passed as C integers. */
53 58
54EMACS_INT 59size_t
55doprnt (char *buffer, register int bufsize, const char *format, 60doprnt (char *buffer, register size_t bufsize, const char *format,
56 const char *format_end, va_list ap) 61 const char *format_end, va_list ap)
57{ 62{
58 const char *fmt = format; /* Pointer into format string */ 63 const char *fmt = format; /* Pointer into format string */
@@ -62,15 +67,15 @@ doprnt (char *buffer, register int bufsize, const char *format,
62 char tembuf[DBL_MAX_10_EXP + 100]; 67 char tembuf[DBL_MAX_10_EXP + 100];
63 68
64 /* Size of sprintf_buffer. */ 69 /* Size of sprintf_buffer. */
65 unsigned size_allocated = sizeof (tembuf); 70 size_t size_allocated = sizeof (tembuf);
66 71
67 /* Buffer to use for sprintf. Either tembuf or same as BIG_BUFFER. */ 72 /* Buffer to use for sprintf. Either tembuf or same as BIG_BUFFER. */
68 char *sprintf_buffer = tembuf; 73 char *sprintf_buffer = tembuf;
69 74
70 /* Buffer we have got with malloc. */ 75 /* Buffer we have got with malloc. */
71 char *big_buffer = 0; 76 char *big_buffer = NULL;
72 77
73 register int tem; 78 register size_t tem;
74 char *string; 79 char *string;
75 char fixed_buffer[20]; /* Default buffer for small formatting. */ 80 char fixed_buffer[20]; /* Default buffer for small formatting. */
76 char *fmtcpy; 81 char *fmtcpy;
@@ -92,8 +97,9 @@ doprnt (char *buffer, register int bufsize, const char *format,
92 { 97 {
93 if (*fmt == '%') /* Check for a '%' character */ 98 if (*fmt == '%') /* Check for a '%' character */
94 { 99 {
95 unsigned size_bound = 0; 100 size_t size_bound = 0;
96 EMACS_INT width; /* Columns occupied by STRING. */ 101 EMACS_INT width; /* Columns occupied by STRING on display. */
102 int long_flag = 0;
97 103
98 fmt++; 104 fmt++;
99 /* Copy this one %-spec into fmtcpy. */ 105 /* Copy this one %-spec into fmtcpy. */
@@ -108,10 +114,11 @@ doprnt (char *buffer, register int bufsize, const char *format,
108 This might be a field width or a precision; e.g. 114 This might be a field width or a precision; e.g.
109 %1.1000f and %1000.1f both might need 1000+ bytes. 115 %1.1000f and %1000.1f both might need 1000+ bytes.
110 Parse the width or precision, checking for overflow. */ 116 Parse the width or precision, checking for overflow. */
111 unsigned n = *fmt - '0'; 117 size_t n = *fmt - '0';
112 while ('0' <= fmt[1] && fmt[1] <= '9') 118 while ('0' <= fmt[1] && fmt[1] <= '9')
113 { 119 {
114 if (n * 10 + fmt[1] - '0' < n) 120 if (n >= SIZE_MAX / 10
121 || n * 10 > SIZE_MAX - (fmt[1] - '0'))
115 error ("Format width or precision too large"); 122 error ("Format width or precision too large");
116 n = n * 10 + fmt[1] - '0'; 123 n = n * 10 + fmt[1] - '0';
117 *string++ = *++fmt; 124 *string++ = *++fmt;
@@ -122,6 +129,13 @@ doprnt (char *buffer, register int bufsize, const char *format,
122 } 129 }
123 else if (*fmt == '-' || *fmt == ' ' || *fmt == '.' || *fmt == '+') 130 else if (*fmt == '-' || *fmt == ' ' || *fmt == '.' || *fmt == '+')
124 ; 131 ;
132 else if (*fmt == 'l')
133 {
134 long_flag = 1;
135 if (!strchr ("dox", fmt[1]))
136 /* %l as conversion specifier, not as modifier. */
137 break;
138 }
125 else 139 else
126 break; 140 break;
127 fmt++; 141 fmt++;
@@ -130,7 +144,7 @@ doprnt (char *buffer, register int bufsize, const char *format,
130 144
131 /* Make the size bound large enough to handle floating point formats 145 /* Make the size bound large enough to handle floating point formats
132 with large numbers. */ 146 with large numbers. */
133 if (size_bound + DBL_MAX_10_EXP + 50 < size_bound) 147 if (size_bound > SIZE_MAX - DBL_MAX_10_EXP - 50)
134 error ("Format width or precision too large"); 148 error ("Format width or precision too large");
135 size_bound += DBL_MAX_10_EXP + 50; 149 size_bound += DBL_MAX_10_EXP + 50;
136 150
@@ -151,23 +165,47 @@ doprnt (char *buffer, register int bufsize, const char *format,
151 error ("Invalid format operation %%%c", fmt[-1]); 165 error ("Invalid format operation %%%c", fmt[-1]);
152 166
153/* case 'b': */ 167/* case 'b': */
168 case 'l':
154 case 'd': 169 case 'd':
170 {
171 int i;
172 long l;
173
174 if (long_flag)
175 {
176 l = va_arg(ap, long);
177 sprintf (sprintf_buffer, fmtcpy, l);
178 }
179 else
180 {
181 i = va_arg(ap, int);
182 sprintf (sprintf_buffer, fmtcpy, i);
183 }
184 /* Now copy into final output, truncating as necessary. */
185 string = sprintf_buffer;
186 goto doit;
187 }
188
155 case 'o': 189 case 'o':
156 case 'x': 190 case 'x':
157 if (sizeof (int) == sizeof (EMACS_INT)) 191 {
158 ; 192 unsigned u;
159 else if (sizeof (long) == sizeof (EMACS_INT)) 193 unsigned long ul;
160 /* Insert an `l' the right place. */ 194
161 string[1] = string[0], 195 if (long_flag)
162 string[0] = string[-1], 196 {
163 string[-1] = 'l', 197 ul = va_arg(ap, unsigned long);
164 string++; 198 sprintf (sprintf_buffer, fmtcpy, ul);
165 else 199 }
166 abort (); 200 else
167 sprintf (sprintf_buffer, fmtcpy, va_arg(ap, char *)); 201 {
168 /* Now copy into final output, truncating as nec. */ 202 u = va_arg(ap, unsigned);
169 string = sprintf_buffer; 203 sprintf (sprintf_buffer, fmtcpy, u);
170 goto doit; 204 }
205 /* Now copy into final output, truncating as necessary. */
206 string = sprintf_buffer;
207 goto doit;
208 }
171 209
172 case 'f': 210 case 'f':
173 case 'e': 211 case 'e':
@@ -175,7 +213,7 @@ doprnt (char *buffer, register int bufsize, const char *format,
175 { 213 {
176 double d = va_arg(ap, double); 214 double d = va_arg(ap, double);
177 sprintf (sprintf_buffer, fmtcpy, d); 215 sprintf (sprintf_buffer, fmtcpy, d);
178 /* Now copy into final output, truncating as nec. */ 216 /* Now copy into final output, truncating as necessary. */
179 string = sprintf_buffer; 217 string = sprintf_buffer;
180 goto doit; 218 goto doit;
181 } 219 }
@@ -187,13 +225,18 @@ doprnt (char *buffer, register int bufsize, const char *format,
187 minlen = atoi (&fmtcpy[1]); 225 minlen = atoi (&fmtcpy[1]);
188 string = va_arg (ap, char *); 226 string = va_arg (ap, char *);
189 tem = strlen (string); 227 tem = strlen (string);
228 if (tem > MOST_POSITIVE_FIXNUM)
229 error ("String for %%s or %%S format is too long");
190 width = strwidth (string, tem); 230 width = strwidth (string, tem);
191 goto doit1; 231 goto doit1;
192 232
193 /* Copy string into final output, truncating if no room. */ 233 /* Copy string into final output, truncating if no room. */
194 doit: 234 doit:
195 /* Coming here means STRING contains ASCII only. */ 235 /* Coming here means STRING contains ASCII only. */
196 width = tem = strlen (string); 236 tem = strlen (string);
237 if (tem > MOST_POSITIVE_FIXNUM)
238 error ("Format width or precision too large");
239 width = tem;
197 doit1: 240 doit1:
198 /* We have already calculated: 241 /* We have already calculated:
199 TEM -- length of STRING, 242 TEM -- length of STRING,
@@ -236,13 +279,8 @@ doprnt (char *buffer, register int bufsize, const char *format,
236 279
237 case 'c': 280 case 'c':
238 { 281 {
239 /* Sometimes for %c we pass a char, which would widen 282 int chr = va_arg(ap, int);
240 to int. Sometimes we pass XFASTINT() or XINT() 283 tem = CHAR_STRING (chr, (unsigned char *) charbuf);
241 values, which would be EMACS_INT. Let's hope that
242 both are passed the same way, otherwise we'll need
243 to rewrite callers. */
244 EMACS_INT chr = va_arg(ap, EMACS_INT);
245 tem = CHAR_STRING ((int) chr, (unsigned char *) charbuf);
246 string = charbuf; 284 string = charbuf;
247 string[tem] = 0; 285 string[tem] = 0;
248 width = strwidth (string, tem); 286 width = strwidth (string, tem);
@@ -274,6 +312,6 @@ doprnt (char *buffer, register int bufsize, const char *format,
274 /* If we had to malloc something, free it. */ 312 /* If we had to malloc something, free it. */
275 xfree (big_buffer); 313 xfree (big_buffer);
276 314
277 *bufptr = 0; /* Make sure our string end with a '\0' */ 315 *bufptr = 0; /* Make sure our string ends with a '\0' */
278 return bufptr - buffer; 316 return bufptr - buffer;
279} 317}