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.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs; see the file COPYING. If not, write to
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
34 #ifndef DBL_MAX_10_EXP
35 #define DBL_MAX_10_EXP 308 /* IEEE double */
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
43 extern long *xmalloc (), *xrealloc ();
45 static int doprnt1 ();
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.
53 A double counts as two arguments.
54 String arguments are passed as C strings.
55 Integers are passed as C integers. */
57 doprnt (buffer
, bufsize
, format
, format_end
, nargs
, args
)
65 return doprnt1 (0, buffer
, bufsize
, format
, format_end
, nargs
, args
);
68 /* Like doprnt except that strings in ARGS are passed
71 doprnt_lisp (buffer
, bufsize
, format
, format_end
, nargs
, args
)
79 return doprnt1 (1, buffer
, bufsize
, format
, format_end
, nargs
, args
);
83 doprnt1 (lispstrings
, buffer
, bufsize
, format
, format_end
, nargs
, args
)
92 int cnt
= 0; /* Number of arg to gobble next */
93 register char *fmt
= format
; /* Pointer into format string */
94 register char *bufptr
= buffer
; /* Pointer into output buffer.. */
96 /* Use this for sprintf unless we need something really big. */
97 char tembuf
[DBL_MAX_10_EXP
+ 100];
99 /* Size of sprintf_buffer. */
100 int size_allocated
= sizeof (tembuf
);
102 /* Buffer to use for sprintf. Either tembuf or same as BIG_BUFFER. */
103 char *sprintf_buffer
= tembuf
;
105 /* Buffer we have got with malloc. */
106 char *big_buffer
= 0;
110 char fixed_buffer
[20]; /* Default buffer for small formatting. */
113 int size
; /* Field width factor; e.g., %90d */
114 char charbuf
[5]; /* Used for %c. */
117 format_end
= format
+ strlen (format
);
119 if ((format_end
- format
+ 1) < sizeof (fixed_buffer
))
120 fmtcpy
= fixed_buffer
;
122 fmtcpy
= (char *) alloca (format_end
- format
+ 1);
126 /* Loop until end of format string or buffer full. */
127 while (fmt
!= format_end
&& bufsize
> 0)
129 if (*fmt
== '%') /* Check for a '%' character */
132 int width
; /* Columns occupied by STRING. */
135 /* Copy this one %-spec into fmtcpy. */
141 if ('0' <= *fmt
&& *fmt
<= '9')
143 /* Get an idea of how much space we might need.
144 This might be a field width or a precision; e.g.
145 %1.1000f and %1000.1f both might need 1000+ bytes.
146 Parse the width or precision, checking for overflow. */
148 while ('0' <= fmt
[1] && fmt
[1] <= '9')
151 || (n
= n
* 10 + (fmt
[1] - '0')) < 0)
152 error ("Format width or precision too large");
159 else if (*fmt
== '-' || *fmt
== ' ' || *fmt
== '.')
167 /* Make the size bound large enough to handle floating point formats
168 with large numbers. */
169 size_bound
+= DBL_MAX_10_EXP
+ 50;
172 error ("Format width or precision too large");
174 /* Make sure we have that much. */
175 if (size_bound
> size_allocated
)
178 big_buffer
= (char *) xrealloc (big_buffer
, size_bound
);
180 big_buffer
= (char *) xmalloc (size_bound
);
181 sprintf_buffer
= big_buffer
;
182 size_allocated
= size_bound
;
188 error ("Invalid format operation %%%c", fmt
[-1]);
195 error ("Not enough arguments for format string");
196 if (sizeof (int) == sizeof (EMACS_INT
))
198 else if (sizeof (long) == sizeof (EMACS_INT
))
199 /* Insert an `l' the right place. */
200 string
[1] = string
[0],
201 string
[0] = string
[-1],
206 sprintf (sprintf_buffer
, fmtcpy
, args
[cnt
++]);
207 /* Now copy into final output, truncating as nec. */
208 string
= sprintf_buffer
;
215 union { double d
; char *half
[2]; } u
;
216 if (cnt
+ 1 == nargs
)
217 error ("not enough arguments for format string");
218 u
.half
[0] = args
[cnt
++];
219 u
.half
[1] = args
[cnt
++];
220 sprintf (sprintf_buffer
, fmtcpy
, u
.d
);
221 /* Now copy into final output, truncating as nec. */
222 string
= sprintf_buffer
;
230 error ("not enough arguments for format string");
231 if (fmtcpy
[1] != 's')
232 minlen
= atoi (&fmtcpy
[1]);
235 string
= (char *) ((struct Lisp_String
*)args
[cnt
])->data
;
236 tem
= ((struct Lisp_String
*)args
[cnt
])->size
;
241 string
= args
[cnt
++];
242 tem
= strlen (string
);
244 width
= strwidth (string
, tem
);
247 /* Copy string into final output, truncating if no room. */
249 /* Coming here means STRING contains ASCII only. */
250 width
= tem
= strlen (string
);
252 /* We have already calculated:
253 TEM -- length of STRING,
254 WIDTH -- columns occupied by STRING when displayed, and
255 MINLEN -- minimum columns of the output. */
258 while (minlen
> width
&& bufsize
> 0)
268 /* Truncate the string at character boundary. */
270 while (!CHAR_HEAD_P (string
+ tem
- 1)) tem
--;
271 bcopy (string
, bufptr
, tem
);
272 /* We must calculate WIDTH again. */
273 width
= strwidth (bufptr
, tem
);
276 bcopy (string
, bufptr
, tem
);
281 while (minlen
< - width
&& bufsize
> 0)
293 error ("not enough arguments for format string");
294 tem
= CHAR_STRING ((EMACS_INT
) args
[cnt
], charbuf
, string
);
297 width
= strwidth (string
, tem
);
298 if (fmtcpy
[1] != 'c')
299 minlen
= atoi (&fmtcpy
[1]);
303 fmt
--; /* Drop thru and this % will be treated as normal */
308 /* Just some character; Copy it if the whole multi-byte form
309 fit in the buffer. */
310 char *save_bufptr
= bufptr
;
312 do { *bufptr
++ = *fmt
++; }
313 while (--bufsize
> 0 && !CHAR_HEAD_P (fmt
));
314 if (!CHAR_HEAD_P (fmt
))
316 bufptr
= save_bufptr
;
322 /* If we had to malloc something, free it. */
326 *bufptr
= 0; /* Make sure our string end with a '\0' */
327 return bufptr
- buffer
;