chiark / gitweb /
Ship unihash test vectors.
[mLib] / dputf.c
CommitLineData
002eaee3 1/* -*-c-*-
2 *
8656dc50 3 * $Id: dputf.c,v 1.6 2004/04/08 01:36:11 mdw Exp $
002eaee3 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
002eaee3 30/*----- Header files ------------------------------------------------------*/
31
32#include <ctype.h>
002eaee3 33#include <math.h>
34#include <stdarg.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38
5d45633f 39#ifdef HAVE_FLOAT_H
40# include <float.h>
41#endif
42
002eaee3 43#include "dstr.h"
44
45/*----- Tunable constants -------------------------------------------------*/
46
47/*
48 * For each format specifier, at least @DSTR_PUTFSTEP@ bytes are ensured
49 * before writing the formatted result.
50 */
51
52#define DSTR_PUTFSTEP 64 /* Buffer size for @putf@ */
53
54/*----- Main code ---------------------------------------------------------*/
55
56/* --- @dstr_vputf@ --- *
57 *
58 * Arguments: @dstr *d@ = pointer to a dynamic string block
59 * @const char *p@ = pointer to @printf@-style format string
5a18a126 60 * @va_list *ap@ = argument handle
002eaee3 61 *
62 * Returns: The number of characters written to the string.
63 *
64 * Use: As for @dstr_putf@, but may be used as a back-end to user-
65 * supplied functions with @printf@-style interfaces.
66 */
67
5a18a126 68int dstr_vputf(dstr *d, const char *p, va_list *ap)
002eaee3 69{
70 const char *q = p;
71 size_t n = d->len;
72 size_t sz;
73 dstr dd = DSTR_INIT;
74
75 while (*p) {
76 unsigned f;
77 int wd, prec;
78
393cf1d9 79#define f_short 1u
80#define f_long 2u
81#define f_Long 4u
82#define f_wd 8u
83#define f_prec 16u
002eaee3 84
85 /* --- Most stuff gets passed on through --- */
86
87 if (*p != '%') {
88 p++;
89 continue;
90 }
91
92 /* --- Dump out what's between @q@ and @p@ --- */
93
94 DPUTM(d, q, p - q);
95 p++;
96
97 /* --- Sort out the various silly flags and things --- */
98
99 DPUTC(&dd, '%');
100 f = 0;
101 sz = DSTR_PUTFSTEP;
102
103 for (;;) {
104 switch (*p) {
105
106 /* --- Various simple flags --- */
107
108 case '+':
109 case '-':
110 case '#':
111 case '0':
112 goto putch;
113 case 'h':
114 f |= f_short;
115 goto putch;
116 case 'l':
117 f |= f_long;
118 goto putch;
119 case 'L':
120 f |= f_Long;
121 goto putch;
122 case 0:
123 goto finished;
124
125 /* --- Field widths and precision specifiers --- */
126
127 {
128 int *ip;
129
130 case '.':
131 DPUTC(&dd, '.');
132 ip = &prec;
133 f |= f_prec;
134 goto getnum;
135 case '*':
136 ip = &wd;
137 f |= f_wd;
138 goto getnum;
139 default:
140 if (isdigit((unsigned char)*p)) {
141 f |= f_wd;
142 ip = &wd;
143 goto getnum;
144 }
145 DPUTC(d, *p);
146 goto formatted;
147 getnum:
148 *ip = 0;
149 if (*p == '*') {
5a18a126 150 *ip = va_arg(*ap, int);
002eaee3 151 DENSURE(&dd, DSTR_PUTFSTEP);
152 dd.len += sprintf(dd.buf + dd.len, "%i", *ip);
153 } else {
154 *ip = *p - '0';
155 DPUTC(&dd, *p);
156 p++;
157 while (isdigit((unsigned char)*p)) {
158 DPUTC(&dd, *p);
159 *ip = 10 * *ip + *p++ - '0';
160 }
161 }
162 break;
163 }
164
165 /* --- Output formatting --- */
166
167 case 'd': case 'i': case 'x': case 'X': case 'o': case 'u':
168 DPUTC(&dd, *p);
169 DPUTZ(&dd);
170 if ((f & f_prec) && prec + 16 > sz)
171 sz = prec + 16;
172 if ((f & f_wd) && wd + 1> sz)
173 sz = wd + 1;
174 DENSURE(d, sz);
175 if (f & f_long)
176 d->len += sprintf(d->buf + d->len, dd.buf,
5a18a126 177 va_arg(*ap, unsigned long));
002eaee3 178 else
179 d->len += sprintf(d->buf + d->len, dd.buf,
5a18a126 180 va_arg(*ap, unsigned int));
002eaee3 181 goto formatted;
182
183 case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
5d45633f 184#ifdef HAVE_FLOAT_H
002eaee3 185 DPUTC(&dd, *p);
186 DPUTZ(&dd);
187 if (*p == 'f') {
188 size_t mx = (f & f_Long ? LDBL_MAX_10_EXP : DBL_MAX_10_EXP) + 16;
189 if (mx > sz)
190 sz = mx;
191 }
393cf1d9 192 if (!(f & f_prec))
002eaee3 193 prec = 6;
393cf1d9 194 else
002eaee3 195 sz += prec + 16;
196 if ((f & f_wd) && wd + 1 > sz)
197 sz = wd + 1;
198 DENSURE(d, sz);
199 if (f & f_Long)
200 d->len += sprintf(d->buf + d->len, dd.buf,
5a18a126 201 va_arg(*ap, long double));
002eaee3 202 else
203 d->len += sprintf(d->buf + d->len, dd.buf,
5a18a126 204 va_arg(*ap, double));
002eaee3 205 goto formatted;
5d45633f 206#else
207 DPUTS(d, "<no float support>");
208#endif
002eaee3 209
210 case 'c':
211 DPUTC(&dd, *p);
212 DPUTZ(&dd);
213 if ((f & f_wd) && wd + 1> sz)
214 sz = wd + 1;
215 DENSURE(d, sz);
216 d->len += sprintf(d->buf + d->len, dd.buf,
5a18a126 217 va_arg(*ap, unsigned));
002eaee3 218 goto formatted;
219
220 case 's': {
5a18a126 221 const char *s = va_arg(*ap, const char *);
002eaee3 222 sz = strlen(s);
223 DPUTC(&dd, *p);
224 DPUTZ(&dd);
225 if (f & f_prec)
226 sz = prec;
227 if ((f & f_wd) && wd > sz)
228 sz = wd;
229 DENSURE(d, sz + 1);
230 d->len += sprintf(d->buf + d->len, dd.buf, s);
231 goto formatted;
232 }
233
234 case 'p':
235 DPUTC(&dd, *p);
236 DPUTZ(&dd);
237 if ((f & f_prec) && prec + 16 > sz)
238 sz = prec + 16;
239 if ((f & f_wd) && wd + 1> sz)
240 sz = wd + 1;
241 DENSURE(d, sz);
242 d->len += sprintf(d->buf + d->len, dd.buf,
5a18a126 243 va_arg(*ap, const void *));
002eaee3 244 goto formatted;
245
246 case 'n':
247 if (f & f_long)
5a18a126 248 *va_arg(*ap, long *) = (long)(d->len - n);
002eaee3 249 else if (f & f_short)
5a18a126 250 *va_arg(*ap, short *) = (short)(d->len - n);
002eaee3 251 else
5a18a126 252 *va_arg(*ap, int *) = (int)(d->len - n);
002eaee3 253 goto formatted;
254
255 /* --- Other random stuff --- */
256
257 putch:
258 DPUTC(&dd, *p);
259 p++;
260 break;
261 }
262 }
263
264 formatted:
265 DRESET(&dd);
266 q = ++p;
393cf1d9 267
268#undef f_short
269#undef f_long
270#undef f_Long
271#undef f_wd
272#undef f_prec
002eaee3 273 }
274
275 DPUTM(d, q, p - q);
276finished:
277 DPUTZ(d);
278 DDESTROY(&dd);
279 return (d->len - n);
280}
281
282/* --- @dstr_putf@ --- *
283 *
284 * Arguments: @dstr *d@ = pointer to a dynamic string block
285 * @const char *p@ = pointer to @printf@-style format string
286 * @...@ = argument handle
287 *
288 * Returns: The number of characters written to the string.
289 *
290 * Use: Writes a piece of text to a dynamic string, doing @printf@-
291 * style substitutions as it goes. Intended to be robust if
292 * faced with malicious arguments, but not if the format string
293 * itself is malicious.
294 */
295
296int dstr_putf(dstr *d, const char *p, ...)
297{
298 int n;
299 va_list ap;
300 va_start(ap, p);
5a18a126 301 n = dstr_vputf(d, p, &ap);
002eaee3 302 va_end(ap);
303 return (n);
304}
305
306/*----- That's all, folks -------------------------------------------------*/