]> code.delx.au - gnu-emacs/blob - src/doprnt.c
[HAVE_NTGUI] (FRAME_TERMCAP_P): Don't redefine.
[gnu-emacs] / src / doprnt.c
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
6 This file is part of GNU Emacs.
7
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)
11 any later version.
12
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.
17
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, 675 Mass Ave, Cambridge, MA 02139, USA. */
21
22
23 #include <config.h>
24 #include <stdio.h>
25 #include <ctype.h>
26
27 extern long *xmalloc (), *xrealloc ();
28
29 /* Generate output from a format-spec FORMAT,
30 terminated at position FORMAT_END.
31 Output goes in BUFFER, which has room for BUFSIZE chars.
32 If the output does not fit, truncate it to fit.
33 Returns the number of characters stored into BUFFER.
34 ARGS points to the vector of arguments, and NARGS says how many.
35 A double counts as two arguments. */
36
37 doprnt (buffer, bufsize, format, format_end, nargs, args)
38 char *buffer;
39 register int bufsize;
40 char *format;
41 char *format_end;
42 int nargs;
43 char **args;
44 {
45 int cnt = 0; /* Number of arg to gobble next */
46 register char *fmt = format; /* Pointer into format string */
47 register char *bufptr = buffer; /* Pointer into output buffer.. */
48
49 /* Use this for sprintf unless we need something really big. */
50 char tembuf[100];
51
52 /* Size of sprintf_buffer. */
53 int size_allocated = 100;
54
55 /* Buffer to use for sprintf. Either tembuf or same as BIG_BUFFER. */
56 char *sprintf_buffer = tembuf;
57
58 /* Buffer we have got with malloc. */
59 char *big_buffer = 0;
60
61 register int tem;
62 char *string;
63 char fixed_buffer[20]; /* Default buffer for small formatting. */
64 char *fmtcpy;
65 int minlen;
66 int size; /* Field width factor; e.g., %90d */
67 char charbuf[2]; /* Used for %c. */
68
69 if (format_end == 0)
70 format_end = format + strlen (format);
71
72 if ((format_end - format + 1) < sizeof (fixed_buffer))
73 fmtcpy = fixed_buffer;
74 else
75 fmtcpy = (char *) alloca (format_end - format + 1);
76
77 bufsize--;
78
79 /* Loop until end of format string or buffer full. */
80 while (fmt != format_end && bufsize > 0)
81 {
82 if (*fmt == '%') /* Check for a '%' character */
83 {
84 int size_bound;
85
86 fmt++;
87 /* Copy this one %-spec into fmtcpy. */
88 string = fmtcpy;
89 *string++ = '%';
90 while (1)
91 {
92 *string++ = *fmt;
93 if (! (*fmt >= '0' && *fmt <= '9')
94 && *fmt != '-' && *fmt != ' '&& *fmt != '.')
95 break;
96 fmt++;
97 }
98 *string = 0;
99 /* Get an idea of how much space we might need. */
100 size_bound = atoi (&fmtcpy[1]);
101
102 /* Avoid pitfall of negative "size" parameter ("%-200d"). */
103 if (size_bound < 0)
104 size_bound = -size_bound;
105 size_bound += 50;
106
107 if (size_bound > (unsigned) (1 << (BITS_PER_INT - 1)))
108 error ("Format padding too large");
109
110 /* Make sure we have that much. */
111 if (size_bound > size_allocated)
112 {
113 if (big_buffer)
114 big_buffer = (char *) xrealloc (big_buffer, size_bound);
115 else
116 big_buffer = (char *) xmalloc (size_bound);
117 sprintf_buffer = big_buffer;
118 size_allocated = size_bound;
119 }
120 minlen = 0;
121 switch (*fmt++)
122 {
123 default:
124 error ("Invalid format operation %%%c", fmt[-1]);
125
126 /* case 'b': */
127 case 'd':
128 case 'o':
129 case 'x':
130 if (cnt == nargs)
131 error ("Not enough arguments for format string");
132 if (sizeof (int) == sizeof (EMACS_INT))
133 ;
134 else if (sizeof (long) == sizeof (EMACS_INT))
135 /* Insert an `l' the right place. */
136 string[1] = string[0],
137 string[0] = string[-1],
138 string[-1] = 'l',
139 string++;
140 else
141 abort ();
142 sprintf (sprintf_buffer, fmtcpy, args[cnt++]);
143 /* Now copy into final output, truncating as nec. */
144 string = sprintf_buffer;
145 goto doit;
146
147 case 'f':
148 case 'e':
149 case 'g':
150 {
151 union { double d; char *half[2]; } u;
152 if (cnt + 1 == nargs)
153 error ("not enough arguments for format string");
154 u.half[0] = args[cnt++];
155 u.half[1] = args[cnt++];
156 sprintf (sprintf_buffer, fmtcpy, u.d);
157 /* Now copy into final output, truncating as nec. */
158 string = sprintf_buffer;
159 goto doit;
160 }
161
162 case 'S':
163 string[-1] = 's';
164 case 's':
165 if (cnt == nargs)
166 error ("not enough arguments for format string");
167 string = args[cnt++];
168 if (fmtcpy[1] != 's')
169 minlen = atoi (&fmtcpy[1]);
170 /* Copy string into final output, truncating if no room. */
171 doit:
172 tem = strlen (string);
173 doit1:
174 if (minlen > 0)
175 {
176 while (minlen > tem && bufsize > 0)
177 {
178 *bufptr++ = ' ';
179 bufsize--;
180 minlen--;
181 }
182 minlen = 0;
183 }
184 if (tem > bufsize)
185 tem = bufsize;
186 strncpy (bufptr, string, tem);
187 bufptr += tem;
188 bufsize -= tem;
189 if (minlen < 0)
190 {
191 while (minlen < - tem && bufsize > 0)
192 {
193 *bufptr++ = ' ';
194 bufsize--;
195 minlen++;
196 }
197 minlen = 0;
198 }
199 continue;
200
201 case 'c':
202 if (cnt == nargs)
203 error ("not enough arguments for format string");
204 *charbuf = (EMACS_INT) args[cnt++];
205 string = charbuf;
206 tem = 1;
207 if (fmtcpy[1] != 'c')
208 minlen = atoi (&fmtcpy[1]);
209 goto doit1;
210
211 case '%':
212 fmt--; /* Drop thru and this % will be treated as normal */
213 }
214 }
215 *bufptr++ = *fmt++; /* Just some characters; Copy 'em */
216 bufsize--;
217 };
218
219 /* If we had to malloc something, free it. */
220 if (big_buffer)
221 xfree (big_buffer);
222
223 *bufptr = 0; /* Make sure our string end with a '\0' */
224 return bufptr - buffer;
225 }