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