(DISP_CHAR_VECTOR): Always return nil for multibyte
[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>
1513af9e 27#include "lisp.h"
24f98398 28
be65c2f4
PE
29#if STDC_HEADERS
30#include <float.h>
31#endif
32
33#ifndef DBL_MAX_10_EXP
34#define DBL_MAX_10_EXP 308 /* IEEE double */
35#endif
36
1077c789
RS
37extern long *xmalloc (), *xrealloc ();
38
1513af9e
RS
39static int doprnt1 ();
40
f4c730d3
RS
41/* Generate output from a format-spec FORMAT,
42 terminated at position FORMAT_END.
43 Output goes in BUFFER, which has room for BUFSIZE chars.
44 If the output does not fit, truncate it to fit.
45 Returns the number of characters stored into BUFFER.
46 ARGS points to the vector of arguments, and NARGS says how many.
1513af9e
RS
47 A double counts as two arguments.
48 String arguments are passed as C strings.
49 Integers are passed as C integers. */
f4c730d3 50
24f98398
JA
51doprnt (buffer, bufsize, format, format_end, nargs, args)
52 char *buffer;
53 register int bufsize;
54 char *format;
55 char *format_end;
56 int nargs;
57 char **args;
1513af9e
RS
58{
59 return doprnt1 (0, buffer, bufsize, format, format_end, nargs, args);
60}
61
62/* Like doprnt except that strings in ARGS are passed
63 as Lisp_Object. */
64
65doprnt_lisp (buffer, bufsize, format, format_end, nargs, args)
66 char *buffer;
67 register int bufsize;
68 char *format;
69 char *format_end;
70 int nargs;
71 char **args;
72{
73 return doprnt1 (1, buffer, bufsize, format, format_end, nargs, args);
74}
75
76static int
77doprnt1 (lispstrings, buffer, bufsize, format, format_end, nargs, args)
78 int lispstrings;
79 char *buffer;
80 register int bufsize;
81 char *format;
82 char *format_end;
83 int nargs;
84 char **args;
24f98398
JA
85{
86 int cnt = 0; /* Number of arg to gobble next */
87 register char *fmt = format; /* Pointer into format string */
88 register char *bufptr = buffer; /* Pointer into output buffer.. */
03383aaf 89
f4c730d3 90 /* Use this for sprintf unless we need something really big. */
be65c2f4 91 char tembuf[DBL_MAX_10_EXP + 100];
03383aaf 92
f4c730d3 93 /* Size of sprintf_buffer. */
be65c2f4 94 int size_allocated = sizeof (tembuf);
03383aaf 95
f4c730d3
RS
96 /* Buffer to use for sprintf. Either tembuf or same as BIG_BUFFER. */
97 char *sprintf_buffer = tembuf;
03383aaf 98
f4c730d3
RS
99 /* Buffer we have got with malloc. */
100 char *big_buffer = 0;
03383aaf 101
24f98398
JA
102 register int tem;
103 char *string;
03383aaf
BF
104 char fixed_buffer[20]; /* Default buffer for small formatting. */
105 char *fmtcpy;
24f98398
JA
106 int minlen;
107 int size; /* Field width factor; e.g., %90d */
35a65fce 108 char charbuf[2]; /* Used for %c. */
24f98398
JA
109
110 if (format_end == 0)
111 format_end = format + strlen (format);
112
03383aaf
BF
113 if ((format_end - format + 1) < sizeof (fixed_buffer))
114 fmtcpy = fixed_buffer;
115 else
91098d38 116 fmtcpy = (char *) alloca (format_end - format + 1);
03383aaf 117
24f98398 118 bufsize--;
03383aaf
BF
119
120 /* Loop until end of format string or buffer full. */
121 while (fmt != format_end && bufsize > 0)
24f98398
JA
122 {
123 if (*fmt == '%') /* Check for a '%' character */
124 {
be65c2f4 125 int size_bound = 0;
f4c730d3 126
24f98398 127 fmt++;
d427b66a 128 /* Copy this one %-spec into fmtcpy. */
24f98398
JA
129 string = fmtcpy;
130 *string++ = '%';
03383aaf 131 while (1)
24f98398
JA
132 {
133 *string++ = *fmt;
be65c2f4
PE
134 if ('0' <= *fmt && *fmt <= '9')
135 {
136 /* Get an idea of how much space we might need.
137 This might be a field width or a precision; e.g.
138 %1.1000f and %1000.1f both might need 1000+ bytes.
139 Parse the width or precision, checking for overflow. */
140 int n = *fmt - '0';
141 while ('0' <= fmt[1] && fmt[1] <= '9')
142 {
143 if (n * 10 / 10 != n
144 || (n = n * 10 + (fmt[1] - '0')) < 0)
145 error ("Format width or precision too large");
146 *string++ = *++fmt;
147 }
148
149 if (size_bound < n)
150 size_bound = n;
151 }
152 else if (*fmt == '-' || *fmt == ' ' || *fmt == '.')
153 ;
154 else
24f98398
JA
155 break;
156 fmt++;
157 }
158 *string = 0;
03383aaf 159
be65c2f4
PE
160 /* Make the size bound large enough to handle floating point formats
161 with large numbers. */
162 size_bound += DBL_MAX_10_EXP + 50;
03383aaf 163
be65c2f4
PE
164 if (size_bound < 0)
165 error ("Format width or precision too large");
6e951728 166
f4c730d3
RS
167 /* Make sure we have that much. */
168 if (size_bound > size_allocated)
169 {
170 if (big_buffer)
171 big_buffer = (char *) xrealloc (big_buffer, size_bound);
172 else
173 big_buffer = (char *) xmalloc (size_bound);
174 sprintf_buffer = big_buffer;
175 size_allocated = size_bound;
176 }
24f98398
JA
177 minlen = 0;
178 switch (*fmt++)
179 {
180 default:
181 error ("Invalid format operation %%%c", fmt[-1]);
182
183/* case 'b': */
184 case 'd':
185 case 'o':
186 case 'x':
187 if (cnt == nargs)
6e951728 188 error ("Not enough arguments for format string");
f9fa352f
RS
189 if (sizeof (int) == sizeof (EMACS_INT))
190 ;
191 else if (sizeof (long) == sizeof (EMACS_INT))
192 /* Insert an `l' the right place. */
193 string[1] = string[0],
194 string[0] = string[-1],
195 string[-1] = 'l',
196 string++;
197 else
198 abort ();
f4c730d3
RS
199 sprintf (sprintf_buffer, fmtcpy, args[cnt++]);
200 /* Now copy into final output, truncating as nec. */
201 string = sprintf_buffer;
24f98398
JA
202 goto doit;
203
f4c730d3
RS
204 case 'f':
205 case 'e':
206 case 'g':
207 {
208 union { double d; char *half[2]; } u;
209 if (cnt + 1 == nargs)
ee0c28e3 210 error ("not enough arguments for format string");
f4c730d3
RS
211 u.half[0] = args[cnt++];
212 u.half[1] = args[cnt++];
213 sprintf (sprintf_buffer, fmtcpy, u.d);
214 /* Now copy into final output, truncating as nec. */
215 string = sprintf_buffer;
216 goto doit;
217 }
218
24f98398
JA
219 case 'S':
220 string[-1] = 's';
221 case 's':
222 if (cnt == nargs)
ee0c28e3 223 error ("not enough arguments for format string");
24f98398
JA
224 if (fmtcpy[1] != 's')
225 minlen = atoi (&fmtcpy[1]);
1513af9e
RS
226 if (lispstrings)
227 {
857c4c67
RS
228 string = (char *) ((struct Lisp_String *)args[cnt])->data;
229 tem = ((struct Lisp_String *)args[cnt])->size;
1513af9e
RS
230 cnt++;
231 }
232 else
233 {
234 string = args[cnt++];
235 tem = strlen (string);
236 }
237 goto doit1;
238
24f98398
JA
239 /* Copy string into final output, truncating if no room. */
240 doit:
241 tem = strlen (string);
35a65fce 242 doit1:
24f98398
JA
243 if (minlen > 0)
244 {
245 while (minlen > tem && bufsize > 0)
246 {
247 *bufptr++ = ' ';
248 bufsize--;
249 minlen--;
250 }
251 minlen = 0;
252 }
253 if (tem > bufsize)
254 tem = bufsize;
1513af9e 255 bcopy (string, bufptr, tem);
24f98398
JA
256 bufptr += tem;
257 bufsize -= tem;
258 if (minlen < 0)
259 {
260 while (minlen < - tem && bufsize > 0)
261 {
262 *bufptr++ = ' ';
263 bufsize--;
264 minlen++;
265 }
266 minlen = 0;
267 }
268 continue;
269
270 case 'c':
271 if (cnt == nargs)
ee0c28e3 272 error ("not enough arguments for format string");
1077c789 273 *charbuf = (EMACS_INT) args[cnt++];
35a65fce
RS
274 string = charbuf;
275 tem = 1;
276 if (fmtcpy[1] != 'c')
277 minlen = atoi (&fmtcpy[1]);
278 goto doit1;
24f98398
JA
279
280 case '%':
281 fmt--; /* Drop thru and this % will be treated as normal */
282 }
283 }
284 *bufptr++ = *fmt++; /* Just some characters; Copy 'em */
285 bufsize--;
286 };
287
f4c730d3
RS
288 /* If we had to malloc something, free it. */
289 if (big_buffer)
9ac0d9e0 290 xfree (big_buffer);
f4c730d3 291
24f98398
JA
292 *bufptr = 0; /* Make sure our string end with a '\0' */
293 return bufptr - buffer;
294}