gnus-registry.el (gnus-registry-ignore-group-p): Don't call `gnus-parameter-registry...
[bpt/emacs.git] / src / doprnt.c
CommitLineData
24f98398 1/* Output like sprintf to a buffer of specified size.
762b15be
EZ
2 Also takes args differently: pass one pointer to the end
3 of the format string in addition to the format string itself.
73b0cd50 4 Copyright (C) 1985, 2001-2011 Free Software Foundation, Inc.
24f98398
JA
5
6This file is part of GNU Emacs.
7
9ec0b715 8GNU Emacs is free software: you can redistribute it and/or modify
24f98398 9it under the terms of the GNU General Public License as published by
9ec0b715
GM
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
24f98398
JA
12
13GNU Emacs is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
9ec0b715 19along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
24f98398 20
762b15be
EZ
21/* If you think about replacing this with some similar standard C function of
22 the printf family (such as vsnprintf), please note that this function
23 supports the following Emacs-specific features:
24
25 . For %c conversions, it produces a string with the multibyte representation
26 of the (`int') argument, suitable for display in an Emacs buffer.
27
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
30 is, it does not assume that each character takes one column on display.
31
32 . If the size of the buffer is not enough to produce the formatted string in
33 its entirety, it makes sure that truncation does not chop the last
34 character in the middle of its multibyte sequence, producing an invalid
35 sequence.
36
37 . It accepts a pointer to the end of the format string, so the format string
38 could include embedded null characters.
39
40 . It signals an error if the length of the formatted string is about to
41 overflow MOST_POSITIVE_FIXNUM, to avoid producing strings longer than what
42 Emacs can handle.
43
44 OTOH, this function supports only a small subset of the standard C formatted
45 output facilities. E.g., %u and %ll are not supported, and precision is
46 largely ignored except for converting floating-point values. However, this
47 is okay, as this function is supposed to be called from `error' and similar
48 functions, and thus does not need to support features beyond those in
49 `Fformat', which is used by `error' on the Lisp level. */
24f98398 50
6d291527 51#include <config.h>
24f98398
JA
52#include <stdio.h>
53#include <ctype.h>
d7306fe6 54#include <setjmp.h>
24f98398 55
cf09633a 56#ifdef STDC_HEADERS
be65c2f4
PE
57#include <float.h>
58#endif
59
48236137 60#include <unistd.h>
48236137 61
e6c3da20
EZ
62#include <limits.h>
63#ifndef SIZE_MAX
64# define SIZE_MAX ((size_t) -1)
65#endif
66
523e9291
RS
67#include "lisp.h"
68
a0ca925c
KH
69/* Since we use the macro CHAR_HEAD_P, we have to include this, but
70 don't have to include others because CHAR_HEAD_P does not contains
71 another macro. */
83be827a 72#include "character.h"
a0ca925c 73
92bc9a36
DN
74#ifndef DBL_MAX_10_EXP
75#define DBL_MAX_10_EXP 308 /* IEEE double */
76#endif
77
f4c730d3
RS
78/* Generate output from a format-spec FORMAT,
79 terminated at position FORMAT_END.
80 Output goes in BUFFER, which has room for BUFSIZE chars.
81 If the output does not fit, truncate it to fit.
6afc669e 82 Returns the number of bytes stored into BUFFER.
f4c730d3 83 ARGS points to the vector of arguments, and NARGS says how many.
1513af9e
RS
84 A double counts as two arguments.
85 String arguments are passed as C strings.
86 Integers are passed as C integers. */
f4c730d3 87
e6c3da20
EZ
88size_t
89doprnt (char *buffer, register size_t bufsize, const char *format,
a8fe7202 90 const char *format_end, va_list ap)
24f98398 91{
a8fe7202 92 const char *fmt = format; /* Pointer into format string */
24f98398 93 register char *bufptr = buffer; /* Pointer into output buffer.. */
03383aaf 94
f4c730d3 95 /* Use this for sprintf unless we need something really big. */
be65c2f4 96 char tembuf[DBL_MAX_10_EXP + 100];
03383aaf 97
f4c730d3 98 /* Size of sprintf_buffer. */
e6c3da20 99 size_t size_allocated = sizeof (tembuf);
03383aaf 100
f4c730d3
RS
101 /* Buffer to use for sprintf. Either tembuf or same as BIG_BUFFER. */
102 char *sprintf_buffer = tembuf;
03383aaf 103
f4c730d3 104 /* Buffer we have got with malloc. */
e6c3da20 105 char *big_buffer = NULL;
03383aaf 106
e6c3da20 107 register size_t tem;
7469ef5d 108 char *string;
03383aaf
BF
109 char fixed_buffer[20]; /* Default buffer for small formatting. */
110 char *fmtcpy;
24f98398 111 int minlen;
7469ef5d 112 char charbuf[MAX_MULTIBYTE_LENGTH + 1]; /* Used for %c. */
24f98398
JA
113
114 if (format_end == 0)
115 format_end = format + strlen (format);
116
03383aaf
BF
117 if ((format_end - format + 1) < sizeof (fixed_buffer))
118 fmtcpy = fixed_buffer;
119 else
91098d38 120 fmtcpy = (char *) alloca (format_end - format + 1);
03383aaf 121
24f98398 122 bufsize--;
03383aaf
BF
123
124 /* Loop until end of format string or buffer full. */
125 while (fmt != format_end && bufsize > 0)
24f98398
JA
126 {
127 if (*fmt == '%') /* Check for a '%' character */
128 {
e6c3da20
EZ
129 size_t size_bound = 0;
130 EMACS_INT width; /* Columns occupied by STRING on display. */
131 int long_flag = 0;
f4c730d3 132
24f98398 133 fmt++;
d427b66a 134 /* Copy this one %-spec into fmtcpy. */
7469ef5d 135 string = fmtcpy;
24f98398 136 *string++ = '%';
03383aaf 137 while (1)
24f98398
JA
138 {
139 *string++ = *fmt;
be65c2f4
PE
140 if ('0' <= *fmt && *fmt <= '9')
141 {
142 /* Get an idea of how much space we might need.
143 This might be a field width or a precision; e.g.
144 %1.1000f and %1000.1f both might need 1000+ bytes.
145 Parse the width or precision, checking for overflow. */
e6c3da20 146 size_t n = *fmt - '0';
be65c2f4
PE
147 while ('0' <= fmt[1] && fmt[1] <= '9')
148 {
e6c3da20
EZ
149 if (n >= SIZE_MAX / 10
150 || n * 10 > SIZE_MAX - (fmt[1] - '0'))
be65c2f4 151 error ("Format width or precision too large");
26898943 152 n = n * 10 + fmt[1] - '0';
be65c2f4
PE
153 *string++ = *++fmt;
154 }
155
156 if (size_bound < n)
157 size_bound = n;
158 }
01769a73 159 else if (*fmt == '-' || *fmt == ' ' || *fmt == '.' || *fmt == '+')
be65c2f4 160 ;
e6c3da20
EZ
161 else if (*fmt == 'l')
162 {
163 long_flag = 1;
164 if (!strchr ("dox", fmt[1]))
165 /* %l as conversion specifier, not as modifier. */
166 break;
167 }
be65c2f4 168 else
24f98398
JA
169 break;
170 fmt++;
171 }
172 *string = 0;
03383aaf 173
be65c2f4
PE
174 /* Make the size bound large enough to handle floating point formats
175 with large numbers. */
e6c3da20 176 if (size_bound > SIZE_MAX - DBL_MAX_10_EXP - 50)
be65c2f4 177 error ("Format width or precision too large");
01769a73 178 size_bound += DBL_MAX_10_EXP + 50;
6e951728 179
f4c730d3
RS
180 /* Make sure we have that much. */
181 if (size_bound > size_allocated)
182 {
183 if (big_buffer)
184 big_buffer = (char *) xrealloc (big_buffer, size_bound);
185 else
186 big_buffer = (char *) xmalloc (size_bound);
187 sprintf_buffer = big_buffer;
188 size_allocated = size_bound;
189 }
24f98398
JA
190 minlen = 0;
191 switch (*fmt++)
192 {
193 default:
194 error ("Invalid format operation %%%c", fmt[-1]);
195
196/* case 'b': */
e6c3da20 197 case 'l':
24f98398 198 case 'd':
e6c3da20
EZ
199 {
200 int i;
201 long l;
202
203 if (long_flag)
204 {
205 l = va_arg(ap, long);
206 sprintf (sprintf_buffer, fmtcpy, l);
207 }
208 else
209 {
210 i = va_arg(ap, int);
211 sprintf (sprintf_buffer, fmtcpy, i);
212 }
213 /* Now copy into final output, truncating as necessary. */
214 string = sprintf_buffer;
215 goto doit;
216 }
217
24f98398
JA
218 case 'o':
219 case 'x':
e6c3da20
EZ
220 {
221 unsigned u;
222 unsigned long ul;
223
224 if (long_flag)
225 {
226 ul = va_arg(ap, unsigned long);
227 sprintf (sprintf_buffer, fmtcpy, ul);
228 }
229 else
230 {
231 u = va_arg(ap, unsigned);
232 sprintf (sprintf_buffer, fmtcpy, u);
233 }
234 /* Now copy into final output, truncating as necessary. */
235 string = sprintf_buffer;
236 goto doit;
237 }
24f98398 238
f4c730d3
RS
239 case 'f':
240 case 'e':
241 case 'g':
242 {
6a8033e1
KR
243 double d = va_arg(ap, double);
244 sprintf (sprintf_buffer, fmtcpy, d);
e6c3da20 245 /* Now copy into final output, truncating as necessary. */
7469ef5d 246 string = sprintf_buffer;
f4c730d3
RS
247 goto doit;
248 }
249
24f98398
JA
250 case 'S':
251 string[-1] = 's';
252 case 's':
24f98398
JA
253 if (fmtcpy[1] != 's')
254 minlen = atoi (&fmtcpy[1]);
7469ef5d 255 string = va_arg (ap, char *);
e267324c 256 tem = strlen (string);
e6c3da20
EZ
257 if (tem > MOST_POSITIVE_FIXNUM)
258 error ("String for %%s or %%S format is too long");
a0ca925c 259 width = strwidth (string, tem);
1513af9e
RS
260 goto doit1;
261
24f98398
JA
262 /* Copy string into final output, truncating if no room. */
263 doit:
a0ca925c 264 /* Coming here means STRING contains ASCII only. */
e6c3da20
EZ
265 tem = strlen (string);
266 if (tem > MOST_POSITIVE_FIXNUM)
267 error ("Format width or precision too large");
268 width = tem;
35a65fce 269 doit1:
a0ca925c
KH
270 /* We have already calculated:
271 TEM -- length of STRING,
272 WIDTH -- columns occupied by STRING when displayed, and
273 MINLEN -- minimum columns of the output. */
24f98398
JA
274 if (minlen > 0)
275 {
a0ca925c 276 while (minlen > width && bufsize > 0)
24f98398
JA
277 {
278 *bufptr++ = ' ';
279 bufsize--;
280 minlen--;
281 }
282 minlen = 0;
283 }
284 if (tem > bufsize)
a0ca925c
KH
285 {
286 /* Truncate the string at character boundary. */
287 tem = bufsize;
a50545d9 288 while (!CHAR_HEAD_P (string[tem - 1])) tem--;
72af86bd 289 memcpy (bufptr, string, tem);
a0ca925c
KH
290 /* We must calculate WIDTH again. */
291 width = strwidth (bufptr, tem);
292 }
293 else
72af86bd 294 memcpy (bufptr, string, tem);
24f98398
JA
295 bufptr += tem;
296 bufsize -= tem;
297 if (minlen < 0)
298 {
a0ca925c 299 while (minlen < - width && bufsize > 0)
24f98398
JA
300 {
301 *bufptr++ = ' ';
302 bufsize--;
303 minlen++;
304 }
305 minlen = 0;
306 }
307 continue;
308
309 case 'c':
6a8033e1 310 {
e6c3da20
EZ
311 int chr = va_arg(ap, int);
312 tem = CHAR_STRING (chr, (unsigned char *) charbuf);
6a8033e1
KR
313 string = charbuf;
314 string[tem] = 0;
315 width = strwidth (string, tem);
316 if (fmtcpy[1] != 'c')
317 minlen = atoi (&fmtcpy[1]);
318 goto doit1;
319 }
24f98398
JA
320
321 case '%':
322 fmt--; /* Drop thru and this % will be treated as normal */
323 }
324 }
a0ca925c
KH
325
326 {
327 /* Just some character; Copy it if the whole multi-byte form
328 fit in the buffer. */
329 char *save_bufptr = bufptr;
330
331 do { *bufptr++ = *fmt++; }
a50545d9
RS
332 while (--bufsize > 0 && !CHAR_HEAD_P (*fmt));
333 if (!CHAR_HEAD_P (*fmt))
a0ca925c
KH
334 {
335 bufptr = save_bufptr;
336 break;
337 }
338 }
24f98398
JA
339 };
340
f4c730d3 341 /* If we had to malloc something, free it. */
70fdbb46 342 xfree (big_buffer);
f4c730d3 343
e6c3da20 344 *bufptr = 0; /* Make sure our string ends with a '\0' */
24f98398
JA
345 return bufptr - buffer;
346}