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