chiark / gitweb /
Fix description of CRCs.
[mLib] / dputf.c
CommitLineData
002eaee3 1/* -*-c-*-
2 *
3 * $Id: dputf.c,v 1.1 1999/10/04 21:44:47 mdw Exp $
4 *
5 * `printf'-style formatting for dynamic strings
6 *
7 * (c) 1999 Straylight/Edgeware
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of the mLib utilities library.
13 *
14 * mLib is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * mLib is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public
25 * License along with mLib; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27 * MA 02111-1307, USA.
28 */
29
30/*----- Revision history --------------------------------------------------*
31 *
32 * $Log: dputf.c,v $
33 * Revision 1.1 1999/10/04 21:44:47 mdw
34 * Move `dstr_putf' and `dstr_vputf' into a separate source file.
35 *
36 */
37
38/*----- Header files ------------------------------------------------------*/
39
40#include <ctype.h>
41#include <float.h>
42#include <math.h>
43#include <stdarg.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <string.h>
47
48#include "dstr.h"
49
50/*----- Tunable constants -------------------------------------------------*/
51
52/*
53 * For each format specifier, at least @DSTR_PUTFSTEP@ bytes are ensured
54 * before writing the formatted result.
55 */
56
57#define DSTR_PUTFSTEP 64 /* Buffer size for @putf@ */
58
59/*----- Main code ---------------------------------------------------------*/
60
61/* --- @dstr_vputf@ --- *
62 *
63 * Arguments: @dstr *d@ = pointer to a dynamic string block
64 * @const char *p@ = pointer to @printf@-style format string
65 * @va_list ap@ = argument handle
66 *
67 * Returns: The number of characters written to the string.
68 *
69 * Use: As for @dstr_putf@, but may be used as a back-end to user-
70 * supplied functions with @printf@-style interfaces.
71 */
72
73int dstr_vputf(dstr *d, const char *p, va_list ap)
74{
75 const char *q = p;
76 size_t n = d->len;
77 size_t sz;
78 dstr dd = DSTR_INIT;
79
80 while (*p) {
81 unsigned f;
82 int wd, prec;
83
84 enum {
85 f_short = 1,
86 f_long = 2,
87 f_Long = 4,
88 f_wd = 8,
89 f_prec = 16
90 };
91
92 /* --- Most stuff gets passed on through --- */
93
94 if (*p != '%') {
95 p++;
96 continue;
97 }
98
99 /* --- Dump out what's between @q@ and @p@ --- */
100
101 DPUTM(d, q, p - q);
102 p++;
103
104 /* --- Sort out the various silly flags and things --- */
105
106 DPUTC(&dd, '%');
107 f = 0;
108 sz = DSTR_PUTFSTEP;
109
110 for (;;) {
111 switch (*p) {
112
113 /* --- Various simple flags --- */
114
115 case '+':
116 case '-':
117 case '#':
118 case '0':
119 goto putch;
120 case 'h':
121 f |= f_short;
122 goto putch;
123 case 'l':
124 f |= f_long;
125 goto putch;
126 case 'L':
127 f |= f_Long;
128 goto putch;
129 case 0:
130 goto finished;
131
132 /* --- Field widths and precision specifiers --- */
133
134 {
135 int *ip;
136
137 case '.':
138 DPUTC(&dd, '.');
139 ip = &prec;
140 f |= f_prec;
141 goto getnum;
142 case '*':
143 ip = &wd;
144 f |= f_wd;
145 goto getnum;
146 default:
147 if (isdigit((unsigned char)*p)) {
148 f |= f_wd;
149 ip = &wd;
150 goto getnum;
151 }
152 DPUTC(d, *p);
153 goto formatted;
154 getnum:
155 *ip = 0;
156 if (*p == '*') {
157 *ip = va_arg(ap, int);
158 DENSURE(&dd, DSTR_PUTFSTEP);
159 dd.len += sprintf(dd.buf + dd.len, "%i", *ip);
160 } else {
161 *ip = *p - '0';
162 DPUTC(&dd, *p);
163 p++;
164 while (isdigit((unsigned char)*p)) {
165 DPUTC(&dd, *p);
166 *ip = 10 * *ip + *p++ - '0';
167 }
168 }
169 break;
170 }
171
172 /* --- Output formatting --- */
173
174 case 'd': case 'i': case 'x': case 'X': case 'o': case 'u':
175 DPUTC(&dd, *p);
176 DPUTZ(&dd);
177 if ((f & f_prec) && prec + 16 > sz)
178 sz = prec + 16;
179 if ((f & f_wd) && wd + 1> sz)
180 sz = wd + 1;
181 DENSURE(d, sz);
182 if (f & f_long)
183 d->len += sprintf(d->buf + d->len, dd.buf,
184 va_arg(ap, unsigned long));
185 else
186 d->len += sprintf(d->buf + d->len, dd.buf,
187 va_arg(ap, unsigned int));
188 goto formatted;
189
190 case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
191 DPUTC(&dd, *p);
192 DPUTZ(&dd);
193 if (*p == 'f') {
194 size_t mx = (f & f_Long ? LDBL_MAX_10_EXP : DBL_MAX_10_EXP) + 16;
195 if (mx > sz)
196 sz = mx;
197 }
198 if ((f & f_prec) == 0)
199 prec = 6;
200 if ((f & f_prec))
201 sz += prec + 16;
202 if ((f & f_wd) && wd + 1 > sz)
203 sz = wd + 1;
204 DENSURE(d, sz);
205 if (f & f_Long)
206 d->len += sprintf(d->buf + d->len, dd.buf,
207 va_arg(ap, long double));
208 else
209 d->len += sprintf(d->buf + d->len, dd.buf,
210 va_arg(ap, double));
211 goto formatted;
212
213 case 'c':
214 DPUTC(&dd, *p);
215 DPUTZ(&dd);
216 if ((f & f_wd) && wd + 1> sz)
217 sz = wd + 1;
218 DENSURE(d, sz);
219 d->len += sprintf(d->buf + d->len, dd.buf,
220 va_arg(ap, unsigned char));
221 goto formatted;
222
223 case 's': {
224 const char *s = va_arg(ap, const char *);
225 sz = strlen(s);
226 DPUTC(&dd, *p);
227 DPUTZ(&dd);
228 if (f & f_prec)
229 sz = prec;
230 if ((f & f_wd) && wd > sz)
231 sz = wd;
232 DENSURE(d, sz + 1);
233 d->len += sprintf(d->buf + d->len, dd.buf, s);
234 goto formatted;
235 }
236
237 case 'p':
238 DPUTC(&dd, *p);
239 DPUTZ(&dd);
240 if ((f & f_prec) && prec + 16 > sz)
241 sz = prec + 16;
242 if ((f & f_wd) && wd + 1> sz)
243 sz = wd + 1;
244 DENSURE(d, sz);
245 d->len += sprintf(d->buf + d->len, dd.buf,
246 va_arg(ap, const void *));
247 goto formatted;
248
249 case 'n':
250 if (f & f_long)
251 *va_arg(ap, long *) = (long)(d->len - n);
252 else if (f & f_short)
253 *va_arg(ap, short *) = (short)(d->len - n);
254 else
255 *va_arg(ap, int *) = (int)(d->len - n);
256 goto formatted;
257
258 /* --- Other random stuff --- */
259
260 putch:
261 DPUTC(&dd, *p);
262 p++;
263 break;
264 }
265 }
266
267 formatted:
268 DRESET(&dd);
269 q = ++p;
270 }
271
272 DPUTM(d, q, p - q);
273finished:
274 DPUTZ(d);
275 DDESTROY(&dd);
276 return (d->len - n);
277}
278
279/* --- @dstr_putf@ --- *
280 *
281 * Arguments: @dstr *d@ = pointer to a dynamic string block
282 * @const char *p@ = pointer to @printf@-style format string
283 * @...@ = argument handle
284 *
285 * Returns: The number of characters written to the string.
286 *
287 * Use: Writes a piece of text to a dynamic string, doing @printf@-
288 * style substitutions as it goes. Intended to be robust if
289 * faced with malicious arguments, but not if the format string
290 * itself is malicious.
291 */
292
293int dstr_putf(dstr *d, const char *p, ...)
294{
295 int n;
296 va_list ap;
297 va_start(ap, p);
298 n = dstr_vputf(d, p, ap);
299 va_end(ap);
300 return (n);
301}
302
303/*----- That's all, folks -------------------------------------------------*/