Convert (most) functions in src to standard C.
[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.
429ab54e 4 Copyright (C) 1985, 2001, 2002, 2003, 2004, 2005,
114f9c96 5 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
24f98398
JA
6
7This file is part of GNU Emacs.
8
9ec0b715 9GNU Emacs is free software: you can redistribute it and/or modify
24f98398 10it under the terms of the GNU General Public License as published by
9ec0b715
GM
11the Free Software Foundation, either version 3 of the License, or
12(at your option) any later version.
24f98398
JA
13
14GNU Emacs is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
9ec0b715 20along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
24f98398
JA
21
22
6d291527 23#include <config.h>
24f98398
JA
24#include <stdio.h>
25#include <ctype.h>
d7306fe6 26#include <setjmp.h>
24f98398 27
cf09633a 28#ifdef STDC_HEADERS
be65c2f4
PE
29#include <float.h>
30#endif
31
48236137
DL
32#ifdef HAVE_UNISTD_H
33#include <unistd.h>
34#endif
35
36#ifdef HAVE_STDLIB_H
37#include <stdlib.h>
38#endif
39
523e9291
RS
40#include "lisp.h"
41
be65c2f4
PE
42#ifndef DBL_MAX_10_EXP
43#define DBL_MAX_10_EXP 308 /* IEEE double */
44#endif
45
a0ca925c
KH
46/* Since we use the macro CHAR_HEAD_P, we have to include this, but
47 don't have to include others because CHAR_HEAD_P does not contains
48 another macro. */
83be827a 49#include "character.h"
a0ca925c 50
1513af9e
RS
51static int doprnt1 ();
52
f4c730d3
RS
53/* Generate output from a format-spec FORMAT,
54 terminated at position FORMAT_END.
55 Output goes in BUFFER, which has room for BUFSIZE chars.
56 If the output does not fit, truncate it to fit.
6afc669e 57 Returns the number of bytes stored into BUFFER.
f4c730d3 58 ARGS points to the vector of arguments, and NARGS says how many.
1513af9e
RS
59 A double counts as two arguments.
60 String arguments are passed as C strings.
61 Integers are passed as C integers. */
f4c730d3 62
dfcf069d 63int
971de7fb 64doprnt (char *buffer, register int bufsize, char *format, char *format_end, int nargs, char **args)
24f98398
JA
65{
66 int cnt = 0; /* Number of arg to gobble next */
67 register char *fmt = format; /* Pointer into format string */
68 register char *bufptr = buffer; /* Pointer into output buffer.. */
03383aaf 69
f4c730d3 70 /* Use this for sprintf unless we need something really big. */
be65c2f4 71 char tembuf[DBL_MAX_10_EXP + 100];
03383aaf 72
f4c730d3 73 /* Size of sprintf_buffer. */
01769a73 74 unsigned size_allocated = sizeof (tembuf);
03383aaf 75
f4c730d3
RS
76 /* Buffer to use for sprintf. Either tembuf or same as BIG_BUFFER. */
77 char *sprintf_buffer = tembuf;
03383aaf 78
f4c730d3
RS
79 /* Buffer we have got with malloc. */
80 char *big_buffer = 0;
03383aaf 81
24f98398 82 register int tem;
c292461f 83 unsigned char *string;
03383aaf
BF
84 char fixed_buffer[20]; /* Default buffer for small formatting. */
85 char *fmtcpy;
24f98398 86 int minlen;
1f625c6c 87 unsigned char charbuf[MAX_MULTIBYTE_LENGTH + 1]; /* Used for %c. */
24f98398
JA
88
89 if (format_end == 0)
90 format_end = format + strlen (format);
91
03383aaf
BF
92 if ((format_end - format + 1) < sizeof (fixed_buffer))
93 fmtcpy = fixed_buffer;
94 else
91098d38 95 fmtcpy = (char *) alloca (format_end - format + 1);
03383aaf 96
24f98398 97 bufsize--;
03383aaf
BF
98
99 /* Loop until end of format string or buffer full. */
100 while (fmt != format_end && bufsize > 0)
24f98398
JA
101 {
102 if (*fmt == '%') /* Check for a '%' character */
103 {
01769a73 104 unsigned size_bound = 0;
a0ca925c 105 int width; /* Columns occupied by STRING. */
f4c730d3 106
24f98398 107 fmt++;
d427b66a 108 /* Copy this one %-spec into fmtcpy. */
01769a73 109 string = (unsigned char *) fmtcpy;
24f98398 110 *string++ = '%';
03383aaf 111 while (1)
24f98398
JA
112 {
113 *string++ = *fmt;
be65c2f4
PE
114 if ('0' <= *fmt && *fmt <= '9')
115 {
116 /* Get an idea of how much space we might need.
117 This might be a field width or a precision; e.g.
118 %1.1000f and %1000.1f both might need 1000+ bytes.
119 Parse the width or precision, checking for overflow. */
01769a73 120 unsigned n = *fmt - '0';
be65c2f4
PE
121 while ('0' <= fmt[1] && fmt[1] <= '9')
122 {
26898943 123 if (n * 10 + fmt[1] - '0' < n)
be65c2f4 124 error ("Format width or precision too large");
26898943 125 n = n * 10 + fmt[1] - '0';
be65c2f4
PE
126 *string++ = *++fmt;
127 }
128
129 if (size_bound < n)
130 size_bound = n;
131 }
01769a73 132 else if (*fmt == '-' || *fmt == ' ' || *fmt == '.' || *fmt == '+')
be65c2f4
PE
133 ;
134 else
24f98398
JA
135 break;
136 fmt++;
137 }
138 *string = 0;
03383aaf 139
be65c2f4
PE
140 /* Make the size bound large enough to handle floating point formats
141 with large numbers. */
01769a73 142 if (size_bound + DBL_MAX_10_EXP + 50 < size_bound)
be65c2f4 143 error ("Format width or precision too large");
01769a73 144 size_bound += DBL_MAX_10_EXP + 50;
6e951728 145
f4c730d3
RS
146 /* Make sure we have that much. */
147 if (size_bound > size_allocated)
148 {
149 if (big_buffer)
150 big_buffer = (char *) xrealloc (big_buffer, size_bound);
151 else
152 big_buffer = (char *) xmalloc (size_bound);
153 sprintf_buffer = big_buffer;
154 size_allocated = size_bound;
155 }
24f98398
JA
156 minlen = 0;
157 switch (*fmt++)
158 {
159 default:
160 error ("Invalid format operation %%%c", fmt[-1]);
161
162/* case 'b': */
163 case 'd':
164 case 'o':
165 case 'x':
166 if (cnt == nargs)
6e951728 167 error ("Not enough arguments for format string");
f9fa352f
RS
168 if (sizeof (int) == sizeof (EMACS_INT))
169 ;
170 else if (sizeof (long) == sizeof (EMACS_INT))
171 /* Insert an `l' the right place. */
172 string[1] = string[0],
173 string[0] = string[-1],
174 string[-1] = 'l',
175 string++;
176 else
177 abort ();
f4c730d3
RS
178 sprintf (sprintf_buffer, fmtcpy, args[cnt++]);
179 /* Now copy into final output, truncating as nec. */
01769a73 180 string = (unsigned char *) sprintf_buffer;
24f98398
JA
181 goto doit;
182
f4c730d3
RS
183 case 'f':
184 case 'e':
185 case 'g':
186 {
187 union { double d; char *half[2]; } u;
188 if (cnt + 1 == nargs)
fb08db45 189 error ("Not enough arguments for format string");
f4c730d3
RS
190 u.half[0] = args[cnt++];
191 u.half[1] = args[cnt++];
192 sprintf (sprintf_buffer, fmtcpy, u.d);
193 /* Now copy into final output, truncating as nec. */
01769a73 194 string = (unsigned char *) sprintf_buffer;
f4c730d3
RS
195 goto doit;
196 }
197
24f98398
JA
198 case 'S':
199 string[-1] = 's';
200 case 's':
201 if (cnt == nargs)
fb08db45 202 error ("Not enough arguments for format string");
24f98398
JA
203 if (fmtcpy[1] != 's')
204 minlen = atoi (&fmtcpy[1]);
e267324c
KR
205 string = (unsigned char *) args[cnt++];
206 tem = strlen (string);
a0ca925c 207 width = strwidth (string, tem);
1513af9e
RS
208 goto doit1;
209
24f98398
JA
210 /* Copy string into final output, truncating if no room. */
211 doit:
a0ca925c
KH
212 /* Coming here means STRING contains ASCII only. */
213 width = tem = strlen (string);
35a65fce 214 doit1:
a0ca925c
KH
215 /* We have already calculated:
216 TEM -- length of STRING,
217 WIDTH -- columns occupied by STRING when displayed, and
218 MINLEN -- minimum columns of the output. */
24f98398
JA
219 if (minlen > 0)
220 {
a0ca925c 221 while (minlen > width && bufsize > 0)
24f98398
JA
222 {
223 *bufptr++ = ' ';
224 bufsize--;
225 minlen--;
226 }
227 minlen = 0;
228 }
229 if (tem > bufsize)
a0ca925c
KH
230 {
231 /* Truncate the string at character boundary. */
232 tem = bufsize;
a50545d9 233 while (!CHAR_HEAD_P (string[tem - 1])) tem--;
a0ca925c
KH
234 bcopy (string, bufptr, tem);
235 /* We must calculate WIDTH again. */
236 width = strwidth (bufptr, tem);
237 }
238 else
239 bcopy (string, bufptr, tem);
24f98398
JA
240 bufptr += tem;
241 bufsize -= tem;
242 if (minlen < 0)
243 {
a0ca925c 244 while (minlen < - width && bufsize > 0)
24f98398
JA
245 {
246 *bufptr++ = ' ';
247 bufsize--;
248 minlen++;
249 }
250 minlen = 0;
251 }
252 continue;
253
254 case 'c':
255 if (cnt == nargs)
fb08db45 256 error ("Not enough arguments for format string");
91f045df
KH
257 tem = CHAR_STRING ((int) (EMACS_INT) args[cnt], charbuf);
258 string = charbuf;
a0ca925c
KH
259 cnt++;
260 string[tem] = 0;
261 width = strwidth (string, tem);
35a65fce
RS
262 if (fmtcpy[1] != 'c')
263 minlen = atoi (&fmtcpy[1]);
264 goto doit1;
24f98398
JA
265
266 case '%':
267 fmt--; /* Drop thru and this % will be treated as normal */
268 }
269 }
a0ca925c
KH
270
271 {
272 /* Just some character; Copy it if the whole multi-byte form
273 fit in the buffer. */
274 char *save_bufptr = bufptr;
275
276 do { *bufptr++ = *fmt++; }
a50545d9
RS
277 while (--bufsize > 0 && !CHAR_HEAD_P (*fmt));
278 if (!CHAR_HEAD_P (*fmt))
a0ca925c
KH
279 {
280 bufptr = save_bufptr;
281 break;
282 }
283 }
24f98398
JA
284 };
285
f4c730d3 286 /* If we had to malloc something, free it. */
70fdbb46 287 xfree (big_buffer);
f4c730d3 288
24f98398
JA
289 *bufptr = 0; /* Make sure our string end with a '\0' */
290 return bufptr - buffer;
291}
6b61353c
KH
292
293/* arch-tag: aa0ab528-7c5f-4c73-894c-aa2526a1efb3
294 (do not change this comment) */