Merge from emacs-23; up to 2010-06-08T03:06:47Z!dann@ics.uci.edu.
[bpt/emacs.git] / src / doprnt.c
CommitLineData
24f98398
JA
1/* Output like sprintf to a buffer of specified size.
2 Also takes args differently: pass one pointer to an array of strings
3 in addition to the format string which is separate.
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
JA
20
21
6d291527 22#include <config.h>
24f98398
JA
23#include <stdio.h>
24#include <ctype.h>
d7306fe6 25#include <setjmp.h>
24f98398 26
cf09633a 27#ifdef STDC_HEADERS
be65c2f4
PE
28#include <float.h>
29#endif
30
48236137 31#include <unistd.h>
48236137 32
523e9291
RS
33#include "lisp.h"
34
a0ca925c
KH
35/* Since we use the macro CHAR_HEAD_P, we have to include this, but
36 don't have to include others because CHAR_HEAD_P does not contains
37 another macro. */
83be827a 38#include "character.h"
a0ca925c 39
92bc9a36
DN
40#ifndef DBL_MAX_10_EXP
41#define DBL_MAX_10_EXP 308 /* IEEE double */
42#endif
43
f4c730d3
RS
44/* Generate output from a format-spec FORMAT,
45 terminated at position FORMAT_END.
46 Output goes in BUFFER, which has room for BUFSIZE chars.
47 If the output does not fit, truncate it to fit.
6afc669e 48 Returns the number of bytes stored into BUFFER.
f4c730d3 49 ARGS points to the vector of arguments, and NARGS says how many.
1513af9e
RS
50 A double counts as two arguments.
51 String arguments are passed as C strings.
52 Integers are passed as C integers. */
f4c730d3 53
84c9ce05 54EMACS_INT
a8fe7202
AS
55doprnt (char *buffer, register int bufsize, const char *format,
56 const char *format_end, va_list ap)
24f98398 57{
a8fe7202 58 const char *fmt = format; /* Pointer into format string */
24f98398 59 register char *bufptr = buffer; /* Pointer into output buffer.. */
03383aaf 60
f4c730d3 61 /* Use this for sprintf unless we need something really big. */
be65c2f4 62 char tembuf[DBL_MAX_10_EXP + 100];
03383aaf 63
f4c730d3 64 /* Size of sprintf_buffer. */
01769a73 65 unsigned size_allocated = sizeof (tembuf);
03383aaf 66
f4c730d3
RS
67 /* Buffer to use for sprintf. Either tembuf or same as BIG_BUFFER. */
68 char *sprintf_buffer = tembuf;
03383aaf 69
f4c730d3
RS
70 /* Buffer we have got with malloc. */
71 char *big_buffer = 0;
03383aaf 72
24f98398 73 register int tem;
7469ef5d 74 char *string;
03383aaf
BF
75 char fixed_buffer[20]; /* Default buffer for small formatting. */
76 char *fmtcpy;
24f98398 77 int minlen;
7469ef5d 78 char charbuf[MAX_MULTIBYTE_LENGTH + 1]; /* Used for %c. */
24f98398
JA
79
80 if (format_end == 0)
81 format_end = format + strlen (format);
82
03383aaf
BF
83 if ((format_end - format + 1) < sizeof (fixed_buffer))
84 fmtcpy = fixed_buffer;
85 else
91098d38 86 fmtcpy = (char *) alloca (format_end - format + 1);
03383aaf 87
24f98398 88 bufsize--;
03383aaf
BF
89
90 /* Loop until end of format string or buffer full. */
91 while (fmt != format_end && bufsize > 0)
24f98398
JA
92 {
93 if (*fmt == '%') /* Check for a '%' character */
94 {
01769a73 95 unsigned size_bound = 0;
84c9ce05 96 EMACS_INT width; /* Columns occupied by STRING. */
f4c730d3 97
24f98398 98 fmt++;
d427b66a 99 /* Copy this one %-spec into fmtcpy. */
7469ef5d 100 string = fmtcpy;
24f98398 101 *string++ = '%';
03383aaf 102 while (1)
24f98398
JA
103 {
104 *string++ = *fmt;
be65c2f4
PE
105 if ('0' <= *fmt && *fmt <= '9')
106 {
107 /* Get an idea of how much space we might need.
108 This might be a field width or a precision; e.g.
109 %1.1000f and %1000.1f both might need 1000+ bytes.
110 Parse the width or precision, checking for overflow. */
01769a73 111 unsigned n = *fmt - '0';
be65c2f4
PE
112 while ('0' <= fmt[1] && fmt[1] <= '9')
113 {
26898943 114 if (n * 10 + fmt[1] - '0' < n)
be65c2f4 115 error ("Format width or precision too large");
26898943 116 n = n * 10 + fmt[1] - '0';
be65c2f4
PE
117 *string++ = *++fmt;
118 }
119
120 if (size_bound < n)
121 size_bound = n;
122 }
01769a73 123 else if (*fmt == '-' || *fmt == ' ' || *fmt == '.' || *fmt == '+')
be65c2f4
PE
124 ;
125 else
24f98398
JA
126 break;
127 fmt++;
128 }
129 *string = 0;
03383aaf 130
be65c2f4
PE
131 /* Make the size bound large enough to handle floating point formats
132 with large numbers. */
01769a73 133 if (size_bound + DBL_MAX_10_EXP + 50 < size_bound)
be65c2f4 134 error ("Format width or precision too large");
01769a73 135 size_bound += DBL_MAX_10_EXP + 50;
6e951728 136
f4c730d3
RS
137 /* Make sure we have that much. */
138 if (size_bound > size_allocated)
139 {
140 if (big_buffer)
141 big_buffer = (char *) xrealloc (big_buffer, size_bound);
142 else
143 big_buffer = (char *) xmalloc (size_bound);
144 sprintf_buffer = big_buffer;
145 size_allocated = size_bound;
146 }
24f98398
JA
147 minlen = 0;
148 switch (*fmt++)
149 {
150 default:
151 error ("Invalid format operation %%%c", fmt[-1]);
152
153/* case 'b': */
154 case 'd':
155 case 'o':
156 case 'x':
f9fa352f
RS
157 if (sizeof (int) == sizeof (EMACS_INT))
158 ;
159 else if (sizeof (long) == sizeof (EMACS_INT))
160 /* Insert an `l' the right place. */
161 string[1] = string[0],
162 string[0] = string[-1],
163 string[-1] = 'l',
164 string++;
165 else
166 abort ();
6a8033e1 167 sprintf (sprintf_buffer, fmtcpy, va_arg(ap, char *));
f4c730d3 168 /* Now copy into final output, truncating as nec. */
7469ef5d 169 string = sprintf_buffer;
24f98398
JA
170 goto doit;
171
f4c730d3
RS
172 case 'f':
173 case 'e':
174 case 'g':
175 {
6a8033e1
KR
176 double d = va_arg(ap, double);
177 sprintf (sprintf_buffer, fmtcpy, d);
f4c730d3 178 /* Now copy into final output, truncating as nec. */
7469ef5d 179 string = sprintf_buffer;
f4c730d3
RS
180 goto doit;
181 }
182
24f98398
JA
183 case 'S':
184 string[-1] = 's';
185 case 's':
24f98398
JA
186 if (fmtcpy[1] != 's')
187 minlen = atoi (&fmtcpy[1]);
7469ef5d 188 string = va_arg (ap, char *);
e267324c 189 tem = strlen (string);
a0ca925c 190 width = strwidth (string, tem);
1513af9e
RS
191 goto doit1;
192
24f98398
JA
193 /* Copy string into final output, truncating if no room. */
194 doit:
a0ca925c
KH
195 /* Coming here means STRING contains ASCII only. */
196 width = tem = strlen (string);
35a65fce 197 doit1:
a0ca925c
KH
198 /* We have already calculated:
199 TEM -- length of STRING,
200 WIDTH -- columns occupied by STRING when displayed, and
201 MINLEN -- minimum columns of the output. */
24f98398
JA
202 if (minlen > 0)
203 {
a0ca925c 204 while (minlen > width && bufsize > 0)
24f98398
JA
205 {
206 *bufptr++ = ' ';
207 bufsize--;
208 minlen--;
209 }
210 minlen = 0;
211 }
212 if (tem > bufsize)
a0ca925c
KH
213 {
214 /* Truncate the string at character boundary. */
215 tem = bufsize;
a50545d9 216 while (!CHAR_HEAD_P (string[tem - 1])) tem--;
72af86bd 217 memcpy (bufptr, string, tem);
a0ca925c
KH
218 /* We must calculate WIDTH again. */
219 width = strwidth (bufptr, tem);
220 }
221 else
72af86bd 222 memcpy (bufptr, string, tem);
24f98398
JA
223 bufptr += tem;
224 bufsize -= tem;
225 if (minlen < 0)
226 {
a0ca925c 227 while (minlen < - width && bufsize > 0)
24f98398
JA
228 {
229 *bufptr++ = ' ';
230 bufsize--;
231 minlen++;
232 }
233 minlen = 0;
234 }
235 continue;
236
237 case 'c':
6a8033e1
KR
238 {
239 /* Sometimes for %c we pass a char, which would widen
240 to int. Sometimes we pass XFASTINT() or XINT()
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);
7469ef5d 245 tem = CHAR_STRING ((int) chr, (unsigned char *) charbuf);
6a8033e1
KR
246 string = charbuf;
247 string[tem] = 0;
248 width = strwidth (string, tem);
249 if (fmtcpy[1] != 'c')
250 minlen = atoi (&fmtcpy[1]);
251 goto doit1;
252 }
24f98398
JA
253
254 case '%':
255 fmt--; /* Drop thru and this % will be treated as normal */
256 }
257 }
a0ca925c
KH
258
259 {
260 /* Just some character; Copy it if the whole multi-byte form
261 fit in the buffer. */
262 char *save_bufptr = bufptr;
263
264 do { *bufptr++ = *fmt++; }
a50545d9
RS
265 while (--bufsize > 0 && !CHAR_HEAD_P (*fmt));
266 if (!CHAR_HEAD_P (*fmt))
a0ca925c
KH
267 {
268 bufptr = save_bufptr;
269 break;
270 }
271 }
24f98398
JA
272 };
273
f4c730d3 274 /* If we had to malloc something, free it. */
70fdbb46 275 xfree (big_buffer);
f4c730d3 276
24f98398
JA
277 *bufptr = 0; /* Make sure our string end with a '\0' */
278 return bufptr - buffer;
279}