summaryrefslogtreecommitdiff
path: root/openbsd-compat/bsd-snprintf.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2005-11-24 19:58:19 +1100
committerDamien Miller <djm@mindrot.org>2005-11-24 19:58:19 +1100
commit57f3915b5513495b11e7052df0260c7896b7b612 (patch)
tree88e15971a1f626cb8ef3ff18d8e9697fef8c2cef /openbsd-compat/bsd-snprintf.c
parentefc17470e0548dae4b6ffc34370ad15562d83239 (diff)
- (djm) [configure.ac openbsd-compat/Makefile.in openbsd-compat/bsd-asprintf.c
openbsd-compat/bsd-snprintf.c openbsd-compat/openbsd-compat.h] Add an asprintf() implementation, after syncing our {v,}snprintf() implementation with some extra fixes from Samba's version. With help and debugging from dtucker and tim; ok dtucker@
Diffstat (limited to 'openbsd-compat/bsd-snprintf.c')
-rw-r--r--openbsd-compat/bsd-snprintf.c610
1 files changed, 380 insertions, 230 deletions
diff --git a/openbsd-compat/bsd-snprintf.c b/openbsd-compat/bsd-snprintf.c
index b5a7ef7a0..ca275abdf 100644
--- a/openbsd-compat/bsd-snprintf.c
+++ b/openbsd-compat/bsd-snprintf.c
@@ -45,45 +45,82 @@
45 * missing. Some systems only have snprintf() but not vsnprintf(), so 45 * missing. Some systems only have snprintf() but not vsnprintf(), so
46 * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. 46 * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
47 * 47 *
48 * Ben Lindstrom <mouring@eviladmin.org> 09/27/00 for OpenSSH 48 * Andrew Tridgell (tridge@samba.org) Oct 1998
49 * Welcome to the world of %lld and %qd support. With other 49 * fixed handling of %.0f
50 * long long support. This is needed for sftp-server to work 50 * added test for HAVE_LONG_DOUBLE
51 * right.
52 * 51 *
53 * Ben Lindstrom <mouring@eviladmin.org> 02/12/01 for OpenSSH 52 * tridge@samba.org, idra@samba.org, April 2001
54 * Removed all hint of VARARGS stuff and banished it to the void, 53 * got rid of fcvt code (twas buggy and made testing harder)
55 * and did a bit of KNF style work to make things a bit more 54 * added C99 semantics
56 * acceptable. Consider stealing from mutt or enlightenment. 55 *
56 * date: 2002/12/19 19:56:31; author: herb; state: Exp; lines: +2 -0
57 * actually print args for %g and %e
58 *
59 * date: 2002/06/03 13:37:52; author: jmcd; state: Exp; lines: +8 -0
60 * Since includes.h isn't included here, VA_COPY has to be defined here. I don't
61 * see any include file that is guaranteed to be here, so I'm defining it
62 * locally. Fixes AIX and Solaris builds.
63 *
64 * date: 2002/06/03 03:07:24; author: tridge; state: Exp; lines: +5 -13
65 * put the ifdef for HAVE_VA_COPY in one place rather than in lots of
66 * functions
67 *
68 * date: 2002/05/17 14:51:22; author: jmcd; state: Exp; lines: +21 -4
69 * Fix usage of va_list passed as an arg. Use __va_copy before using it
70 * when it exists.
71 *
72 * date: 2002/04/16 22:38:04; author: idra; state: Exp; lines: +20 -14
73 * Fix incorrect zpadlen handling in fmtfp.
74 * Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it.
75 * few mods to make it easier to compile the tests.
76 * addedd the "Ollie" test to the floating point ones.
77 *
78 * Martin Pool (mbp@samba.org) April 2003
79 * Remove NO_CONFIG_H so that the test case can be built within a source
80 * tree with less trouble.
81 * Remove unnecessary SAFE_FREE() definition.
82 *
83 * Martin Pool (mbp@samba.org) May 2003
84 * Put in a prototype for dummy_snprintf() to quiet compiler warnings.
85 *
86 * Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
87 * if the C library has some snprintf functions already.
57 **************************************************************/ 88 **************************************************************/
58 89
59#include "includes.h" 90#include "includes.h"
60 91
61RCSID("$Id: bsd-snprintf.c,v 1.9 2004/09/23 11:35:09 dtucker Exp $"); 92RCSID("$Id: bsd-snprintf.c,v 1.10 2005/11/24 08:58:21 djm Exp $");
62 93
63#if defined(BROKEN_SNPRINTF) /* For those with broken snprintf() */ 94#if defined(BROKEN_SNPRINTF) /* For those with broken snprintf() */
64# undef HAVE_SNPRINTF 95# undef HAVE_SNPRINTF
65# undef HAVE_VSNPRINTF 96# undef HAVE_VSNPRINTF
66#endif 97#endif
67 98
68#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) 99#ifndef VA_COPY
69 100# ifdef HAVE_VA_COPY
70static void 101# define VA_COPY(dest, src) va_copy(dest, src)
71dopr(char *buffer, size_t maxlen, const char *format, va_list args); 102# else
72 103# ifdef HAVE___VA_COPY
73static void 104# define VA_COPY(dest, src) __va_copy(dest, src)
74fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, 105# else
75 int min, int max); 106# define VA_COPY(dest, src) (dest) = (src)
107# endif
108# endif
109#endif
76 110
77static void 111#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
78fmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base,
79 int min, int max, int flags);
80 112
81static void 113#ifdef HAVE_LONG_DOUBLE
82fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 114# define LDOUBLE long double
83 int min, int max, int flags); 115#else
116# define LDOUBLE double
117#endif
84 118
85static void 119#ifdef HAVE_LONG_LONG
86dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); 120# define LLONG long long
121#else
122# define LLONG long
123#endif
87 124
88/* 125/*
89 * dopr(): poor man's version of doprintf 126 * dopr(): poor man's version of doprintf
@@ -109,28 +146,49 @@ dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
109#define DP_F_UNSIGNED (1 << 6) 146#define DP_F_UNSIGNED (1 << 6)
110 147
111/* Conversion Flags */ 148/* Conversion Flags */
112#define DP_C_SHORT 1 149#define DP_C_SHORT 1
113#define DP_C_LONG 2 150#define DP_C_LONG 2
114#define DP_C_LDOUBLE 3 151#define DP_C_LDOUBLE 3
115#define DP_C_LONG_LONG 4 152#define DP_C_LLONG 4
116 153
117#define char_to_int(p) (p - '0') 154#define char_to_int(p) ((p)- '0')
118#define abs_val(p) (p < 0 ? -p : p) 155#ifndef MAX
119 156# define MAX(p,q) (((p) >= (q)) ? (p) : (q))
157#endif
120 158
121static void 159static size_t dopr(char *buffer, size_t maxlen, const char *format,
122dopr(char *buffer, size_t maxlen, const char *format, va_list args) 160 va_list args_in);
161static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
162 char *value, int flags, int min, int max);
163static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
164 long value, int base, int min, int max, int flags);
165static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
166 LDOUBLE fvalue, int min, int max, int flags);
167static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
168
169static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
123{ 170{
124 char *strvalue, ch; 171 char ch;
125 long value; 172 LLONG value;
126 long double fvalue; 173 LDOUBLE fvalue;
127 int min = 0, max = -1, state = DP_S_DEFAULT, flags = 0, cflags = 0; 174 char *strvalue;
128 size_t currlen = 0; 175 int min;
129 176 int max;
177 int state;
178 int flags;
179 int cflags;
180 size_t currlen;
181 va_list args;
182
183 VA_COPY(args, args_in);
184
185 state = DP_S_DEFAULT;
186 currlen = flags = cflags = min = 0;
187 max = -1;
130 ch = *format++; 188 ch = *format++;
131 189
132 while (state != DP_S_DONE) { 190 while (state != DP_S_DONE) {
133 if ((ch == '\0') || (currlen >= maxlen)) 191 if (ch == '\0')
134 state = DP_S_DONE; 192 state = DP_S_DONE;
135 193
136 switch(state) { 194 switch(state) {
@@ -138,7 +196,7 @@ dopr(char *buffer, size_t maxlen, const char *format, va_list args)
138 if (ch == '%') 196 if (ch == '%')
139 state = DP_S_FLAGS; 197 state = DP_S_FLAGS;
140 else 198 else
141 dopr_outch(buffer, &currlen, maxlen, ch); 199 dopr_outch (buffer, &currlen, maxlen, ch);
142 ch = *format++; 200 ch = *format++;
143 break; 201 break;
144 case DP_S_FLAGS: 202 case DP_S_FLAGS:
@@ -170,34 +228,37 @@ dopr(char *buffer, size_t maxlen, const char *format, va_list args)
170 break; 228 break;
171 case DP_S_MIN: 229 case DP_S_MIN:
172 if (isdigit((unsigned char)ch)) { 230 if (isdigit((unsigned char)ch)) {
173 min = 10 * min + char_to_int (ch); 231 min = 10*min + char_to_int (ch);
174 ch = *format++; 232 ch = *format++;
175 } else if (ch == '*') { 233 } else if (ch == '*') {
176 min = va_arg (args, int); 234 min = va_arg (args, int);
177 ch = *format++; 235 ch = *format++;
178 state = DP_S_DOT; 236 state = DP_S_DOT;
179 } else 237 } else {
180 state = DP_S_DOT; 238 state = DP_S_DOT;
239 }
181 break; 240 break;
182 case DP_S_DOT: 241 case DP_S_DOT:
183 if (ch == '.') { 242 if (ch == '.') {
184 state = DP_S_MAX; 243 state = DP_S_MAX;
185 ch = *format++; 244 ch = *format++;
186 } else 245 } else {
187 state = DP_S_MOD; 246 state = DP_S_MOD;
247 }
188 break; 248 break;
189 case DP_S_MAX: 249 case DP_S_MAX:
190 if (isdigit((unsigned char)ch)) { 250 if (isdigit((unsigned char)ch)) {
191 if (max < 0) 251 if (max < 0)
192 max = 0; 252 max = 0;
193 max = 10 * max + char_to_int(ch); 253 max = 10*max + char_to_int (ch);
194 ch = *format++; 254 ch = *format++;
195 } else if (ch == '*') { 255 } else if (ch == '*') {
196 max = va_arg (args, int); 256 max = va_arg (args, int);
197 ch = *format++; 257 ch = *format++;
198 state = DP_S_MOD; 258 state = DP_S_MOD;
199 } else 259 } else {
200 state = DP_S_MOD; 260 state = DP_S_MOD;
261 }
201 break; 262 break;
202 case DP_S_MOD: 263 case DP_S_MOD:
203 switch (ch) { 264 switch (ch) {
@@ -208,15 +269,11 @@ dopr(char *buffer, size_t maxlen, const char *format, va_list args)
208 case 'l': 269 case 'l':
209 cflags = DP_C_LONG; 270 cflags = DP_C_LONG;
210 ch = *format++; 271 ch = *format++;
211 if (ch == 'l') { 272 if (ch == 'l') { /* It's a long long */
212 cflags = DP_C_LONG_LONG; 273 cflags = DP_C_LLONG;
213 ch = *format++; 274 ch = *format++;
214 } 275 }
215 break; 276 break;
216 case 'q':
217 cflags = DP_C_LONG_LONG;
218 ch = *format++;
219 break;
220 case 'L': 277 case 'L':
221 cflags = DP_C_LDOUBLE; 278 cflags = DP_C_LDOUBLE;
222 ch = *format++; 279 ch = *format++;
@@ -231,37 +288,37 @@ dopr(char *buffer, size_t maxlen, const char *format, va_list args)
231 case 'd': 288 case 'd':
232 case 'i': 289 case 'i':
233 if (cflags == DP_C_SHORT) 290 if (cflags == DP_C_SHORT)
234 value = va_arg(args, int); 291 value = va_arg (args, int);
235 else if (cflags == DP_C_LONG) 292 else if (cflags == DP_C_LONG)
236 value = va_arg(args, long int); 293 value = va_arg (args, long int);
237 else if (cflags == DP_C_LONG_LONG) 294 else if (cflags == DP_C_LLONG)
238 value = va_arg (args, long long); 295 value = va_arg (args, LLONG);
239 else 296 else
240 value = va_arg (args, int); 297 value = va_arg (args, int);
241 fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags); 298 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
242 break; 299 break;
243 case 'o': 300 case 'o':
244 flags |= DP_F_UNSIGNED; 301 flags |= DP_F_UNSIGNED;
245 if (cflags == DP_C_SHORT) 302 if (cflags == DP_C_SHORT)
246 value = va_arg(args, unsigned int); 303 value = va_arg (args, unsigned int);
247 else if (cflags == DP_C_LONG) 304 else if (cflags == DP_C_LONG)
248 value = va_arg(args, unsigned long int); 305 value = (long)va_arg (args, unsigned long int);
249 else if (cflags == DP_C_LONG_LONG) 306 else if (cflags == DP_C_LLONG)
250 value = va_arg(args, unsigned long long); 307 value = (long)va_arg (args, unsigned LLONG);
251 else 308 else
252 value = va_arg(args, unsigned int); 309 value = (long)va_arg (args, unsigned int);
253 fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags); 310 fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
254 break; 311 break;
255 case 'u': 312 case 'u':
256 flags |= DP_F_UNSIGNED; 313 flags |= DP_F_UNSIGNED;
257 if (cflags == DP_C_SHORT) 314 if (cflags == DP_C_SHORT)
258 value = va_arg(args, unsigned int); 315 value = va_arg (args, unsigned int);
259 else if (cflags == DP_C_LONG) 316 else if (cflags == DP_C_LONG)
260 value = va_arg(args, unsigned long int); 317 value = (long)va_arg (args, unsigned long int);
261 else if (cflags == DP_C_LONG_LONG) 318 else if (cflags == DP_C_LLONG)
262 value = va_arg(args, unsigned long long); 319 value = (LLONG)va_arg (args, unsigned LLONG);
263 else 320 else
264 value = va_arg(args, unsigned int); 321 value = (long)va_arg (args, unsigned int);
265 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); 322 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
266 break; 323 break;
267 case 'X': 324 case 'X':
@@ -269,79 +326,86 @@ dopr(char *buffer, size_t maxlen, const char *format, va_list args)
269 case 'x': 326 case 'x':
270 flags |= DP_F_UNSIGNED; 327 flags |= DP_F_UNSIGNED;
271 if (cflags == DP_C_SHORT) 328 if (cflags == DP_C_SHORT)
272 value = va_arg(args, unsigned int); 329 value = va_arg (args, unsigned int);
273 else if (cflags == DP_C_LONG) 330 else if (cflags == DP_C_LONG)
274 value = va_arg(args, unsigned long int); 331 value = (long)va_arg (args, unsigned long int);
275 else if (cflags == DP_C_LONG_LONG) 332 else if (cflags == DP_C_LLONG)
276 value = va_arg(args, unsigned long long); 333 value = (LLONG)va_arg (args, unsigned LLONG);
277 else 334 else
278 value = va_arg(args, unsigned int); 335 value = (long)va_arg (args, unsigned int);
279 fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags); 336 fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
280 break; 337 break;
281 case 'f': 338 case 'f':
282 if (cflags == DP_C_LDOUBLE) 339 if (cflags == DP_C_LDOUBLE)
283 fvalue = va_arg(args, long double); 340 fvalue = va_arg (args, LDOUBLE);
284 else 341 else
285 fvalue = va_arg(args, double); 342 fvalue = va_arg (args, double);
286 /* um, floating point? */ 343 /* um, floating point? */
287 fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags); 344 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
288 break; 345 break;
289 case 'E': 346 case 'E':
290 flags |= DP_F_UP; 347 flags |= DP_F_UP;
291 case 'e': 348 case 'e':
292 if (cflags == DP_C_LDOUBLE) 349 if (cflags == DP_C_LDOUBLE)
293 fvalue = va_arg(args, long double); 350 fvalue = va_arg (args, LDOUBLE);
294 else 351 else
295 fvalue = va_arg(args, double); 352 fvalue = va_arg (args, double);
353 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
296 break; 354 break;
297 case 'G': 355 case 'G':
298 flags |= DP_F_UP; 356 flags |= DP_F_UP;
299 case 'g': 357 case 'g':
300 if (cflags == DP_C_LDOUBLE) 358 if (cflags == DP_C_LDOUBLE)
301 fvalue = va_arg(args, long double); 359 fvalue = va_arg (args, LDOUBLE);
302 else 360 else
303 fvalue = va_arg(args, double); 361 fvalue = va_arg (args, double);
362 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
304 break; 363 break;
305 case 'c': 364 case 'c':
306 dopr_outch(buffer, &currlen, maxlen, va_arg(args, int)); 365 dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
307 break; 366 break;
308 case 's': 367 case 's':
309 strvalue = va_arg(args, char *); 368 strvalue = va_arg (args, char *);
310 if (max < 0) 369 if (!strvalue) strvalue = "(NULL)";
311 max = maxlen; /* ie, no max */ 370 if (max == -1) {
312 fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max); 371 max = strlen(strvalue);
372 }
373 if (min > 0 && max >= 0 && min > max) max = min;
374 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
313 break; 375 break;
314 case 'p': 376 case 'p':
315 strvalue = va_arg(args, void *); 377 strvalue = va_arg (args, void *);
316 fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); 378 fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
317 break; 379 break;
318 case 'n': 380 case 'n':
319 if (cflags == DP_C_SHORT) { 381 if (cflags == DP_C_SHORT) {
320 short int *num; 382 short int *num;
321 num = va_arg(args, short int *); 383 num = va_arg (args, short int *);
322 *num = currlen; 384 *num = currlen;
323 } else if (cflags == DP_C_LONG) { 385 } else if (cflags == DP_C_LONG) {
324 long int *num; 386 long int *num;
325 num = va_arg(args, long int *); 387 num = va_arg (args, long int *);
326 *num = currlen; 388 *num = (long int)currlen;
327 } else if (cflags == DP_C_LONG_LONG) { 389 } else if (cflags == DP_C_LLONG) {
328 long long *num; 390 LLONG *num;
329 num = va_arg(args, long long *); 391 num = va_arg (args, LLONG *);
330 *num = currlen; 392 *num = (LLONG)currlen;
331 } else { 393 } else {
332 int *num; 394 int *num;
333 num = va_arg(args, int *); 395 num = va_arg (args, int *);
334 *num = currlen; 396 *num = currlen;
335 } 397 }
336 break; 398 break;
337 case '%': 399 case '%':
338 dopr_outch(buffer, &currlen, maxlen, ch); 400 dopr_outch (buffer, &currlen, maxlen, ch);
339 break; 401 break;
340 case 'w': /* not supported yet, treat as next char */ 402 case 'w':
403 /* not supported yet, treat as next char */
341 ch = *format++; 404 ch = *format++;
342 break; 405 break;
343 default: /* Unknown, skip */ 406 default:
344 break; 407 /* Unknown, skip */
408 break;
345 } 409 }
346 ch = *format++; 410 ch = *format++;
347 state = DP_S_DEFAULT; 411 state = DP_S_DEFAULT;
@@ -350,24 +414,33 @@ dopr(char *buffer, size_t maxlen, const char *format, va_list args)
350 break; 414 break;
351 case DP_S_DONE: 415 case DP_S_DONE:
352 break; 416 break;
353 default: /* hmm? */ 417 default:
418 /* hmm? */
354 break; /* some picky compilers need this */ 419 break; /* some picky compilers need this */
355 } 420 }
356 } 421 }
357 if (currlen < maxlen - 1) 422 if (maxlen != 0) {
358 buffer[currlen] = '\0'; 423 if (currlen < maxlen - 1)
359 else 424 buffer[currlen] = '\0';
360 buffer[maxlen - 1] = '\0'; 425 else if (maxlen > 0)
426 buffer[maxlen - 1] = '\0';
427 }
428
429 return currlen;
361} 430}
362 431
363static void 432static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
364fmtstr(char *buffer, size_t *currlen, size_t maxlen, 433 char *value, int flags, int min, int max)
365 char *value, int flags, int min, int max)
366{ 434{
367 int cnt = 0, padlen, strln; /* amount to pad */ 435 int padlen, strln; /* amount to pad */
368 436 int cnt = 0;
369 if (value == 0) 437
438#ifdef DEBUG_SNPRINTF
439 printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
440#endif
441 if (value == 0) {
370 value = "<NULL>"; 442 value = "<NULL>";
443 }
371 444
372 for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */ 445 for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */
373 padlen = min - strln; 446 padlen = min - strln;
@@ -375,18 +448,18 @@ fmtstr(char *buffer, size_t *currlen, size_t maxlen,
375 padlen = 0; 448 padlen = 0;
376 if (flags & DP_F_MINUS) 449 if (flags & DP_F_MINUS)
377 padlen = -padlen; /* Left Justify */ 450 padlen = -padlen; /* Left Justify */
378 451
379 while ((padlen > 0) && (cnt < max)) { 452 while ((padlen > 0) && (cnt < max)) {
380 dopr_outch(buffer, currlen, maxlen, ' '); 453 dopr_outch (buffer, currlen, maxlen, ' ');
381 --padlen; 454 --padlen;
382 ++cnt; 455 ++cnt;
383 } 456 }
384 while (*value && (cnt < max)) { 457 while (*value && (cnt < max)) {
385 dopr_outch(buffer, currlen, maxlen, *value++); 458 dopr_outch (buffer, currlen, maxlen, *value++);
386 ++cnt; 459 ++cnt;
387 } 460 }
388 while ((padlen < 0) && (cnt < max)) { 461 while ((padlen < 0) && (cnt < max)) {
389 dopr_outch(buffer, currlen, maxlen, ' '); 462 dopr_outch (buffer, currlen, maxlen, ' ');
390 ++padlen; 463 ++padlen;
391 ++cnt; 464 ++cnt;
392 } 465 }
@@ -394,49 +467,49 @@ fmtstr(char *buffer, size_t *currlen, size_t maxlen,
394 467
395/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ 468/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
396 469
397static void 470static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
398fmtint(char *buffer, size_t *currlen, size_t maxlen, 471 long value, int base, int min, int max, int flags)
399 long value, int base, int min, int max, int flags)
400{ 472{
473 int signvalue = 0;
401 unsigned long uvalue; 474 unsigned long uvalue;
402 char convert[20]; 475 char convert[20];
403 int signvalue = 0, place = 0, caps = 0; 476 int place = 0;
404 int spadlen = 0; /* amount to space pad */ 477 int spadlen = 0; /* amount to space pad */
405 int zpadlen = 0; /* amount to zero pad */ 478 int zpadlen = 0; /* amount to zero pad */
406 479 int caps = 0;
480
407 if (max < 0) 481 if (max < 0)
408 max = 0; 482 max = 0;
409 483
410 uvalue = value; 484 uvalue = value;
411 485
412 if (!(flags & DP_F_UNSIGNED)) { 486 if(!(flags & DP_F_UNSIGNED)) {
413 if (value < 0) { 487 if( value < 0 ) {
414 signvalue = '-'; 488 signvalue = '-';
415 uvalue = -value; 489 uvalue = -value;
416 } else if (flags & DP_F_PLUS) /* Do a sign (+/i) */ 490 } else {
417 signvalue = '+'; 491 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
418 else if (flags & DP_F_SPACE) 492 signvalue = '+';
419 signvalue = ' '; 493 else if (flags & DP_F_SPACE)
494 signvalue = ' ';
495 }
420 } 496 }
421 497
422 if (flags & DP_F_UP) 498 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
423 caps = 1; /* Should characters be upper case? */ 499
424 do { 500 do {
425 convert[place++] = 501 convert[place++] =
426 (caps ? "0123456789ABCDEF" : "0123456789abcdef") 502 (caps? "0123456789ABCDEF":"0123456789abcdef")
427 [uvalue % (unsigned)base]; 503 [uvalue % (unsigned)base ];
428 uvalue = (uvalue / (unsigned)base ); 504 uvalue = (uvalue / (unsigned)base );
429 } while (uvalue && (place < 20)); 505 } while(uvalue && (place < 20));
430 if (place == 20) 506 if (place == 20) place--;
431 place--;
432 convert[place] = 0; 507 convert[place] = 0;
433 508
434 zpadlen = max - place; 509 zpadlen = max - place;
435 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); 510 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
436 if (zpadlen < 0) 511 if (zpadlen < 0) zpadlen = 0;
437 zpadlen = 0; 512 if (spadlen < 0) spadlen = 0;
438 if (spadlen < 0)
439 spadlen = 0;
440 if (flags & DP_F_ZERO) { 513 if (flags & DP_F_ZERO) {
441 zpadlen = MAX(zpadlen, spadlen); 514 zpadlen = MAX(zpadlen, spadlen);
442 spadlen = 0; 515 spadlen = 0;
@@ -444,27 +517,32 @@ fmtint(char *buffer, size_t *currlen, size_t maxlen,
444 if (flags & DP_F_MINUS) 517 if (flags & DP_F_MINUS)
445 spadlen = -spadlen; /* Left Justifty */ 518 spadlen = -spadlen; /* Left Justifty */
446 519
520#ifdef DEBUG_SNPRINTF
521 printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
522 zpadlen, spadlen, min, max, place);
523#endif
524
447 /* Spaces */ 525 /* Spaces */
448 while (spadlen > 0) { 526 while (spadlen > 0) {
449 dopr_outch(buffer, currlen, maxlen, ' '); 527 dopr_outch (buffer, currlen, maxlen, ' ');
450 --spadlen; 528 --spadlen;
451 } 529 }
452 530
453 /* Sign */ 531 /* Sign */
454 if (signvalue) 532 if (signvalue)
455 dopr_outch(buffer, currlen, maxlen, signvalue); 533 dopr_outch (buffer, currlen, maxlen, signvalue);
456 534
457 /* Zeros */ 535 /* Zeros */
458 if (zpadlen > 0) { 536 if (zpadlen > 0) {
459 while (zpadlen > 0) { 537 while (zpadlen > 0) {
460 dopr_outch(buffer, currlen, maxlen, '0'); 538 dopr_outch (buffer, currlen, maxlen, '0');
461 --zpadlen; 539 --zpadlen;
462 } 540 }
463 } 541 }
464 542
465 /* Digits */ 543 /* Digits */
466 while (place > 0) 544 while (place > 0)
467 dopr_outch(buffer, currlen, maxlen, convert[--place]); 545 dopr_outch (buffer, currlen, maxlen, convert[--place]);
468 546
469 /* Left Justified spaces */ 547 /* Left Justified spaces */
470 while (spadlen < 0) { 548 while (spadlen < 0) {
@@ -473,11 +551,20 @@ fmtint(char *buffer, size_t *currlen, size_t maxlen,
473 } 551 }
474} 552}
475 553
476static long double 554static LDOUBLE abs_val(LDOUBLE value)
477pow10(int exp)
478{ 555{
479 long double result = 1; 556 LDOUBLE result = value;
557
558 if (value < 0)
559 result = -value;
560
561 return result;
562}
480 563
564static LDOUBLE POW10(int exp)
565{
566 LDOUBLE result = 1;
567
481 while (exp) { 568 while (exp) {
482 result *= 10; 569 result *= 10;
483 exp--; 570 exp--;
@@ -486,28 +573,69 @@ pow10(int exp)
486 return result; 573 return result;
487} 574}
488 575
489static long 576static LLONG ROUND(LDOUBLE value)
490round(long double value)
491{ 577{
492 long intpart = value; 578 LLONG intpart;
493
494 value -= intpart;
495 if (value >= 0.5)
496 intpart++;
497 579
580 intpart = (LLONG)value;
581 value = value - intpart;
582 if (value >= 0.5) intpart++;
583
498 return intpart; 584 return intpart;
499} 585}
500 586
501static void 587/* a replacement for modf that doesn't need the math library. Should
502fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 588 be portable, but slow */
503 int min, int max, int flags) 589static double my_modf(double x0, double *iptr)
504{ 590{
505 char iconvert[20], fconvert[20]; 591 int i;
506 int signvalue = 0, iplace = 0, fplace = 0; 592 long l;
593 double x = x0;
594 double f = 1.0;
595
596 for (i=0;i<100;i++) {
597 l = (long)x;
598 if (l <= (x+1) && l >= (x-1)) break;
599 x *= 0.1;
600 f *= 10.0;
601 }
602
603 if (i == 100) {
604 /* yikes! the number is beyond what we can handle. What do we do? */
605 (*iptr) = 0;
606 return 0;
607 }
608
609 if (i != 0) {
610 double i2;
611 double ret;
612
613 ret = my_modf(x0-l*f, &i2);
614 (*iptr) = l*f + i2;
615 return ret;
616 }
617
618 (*iptr) = l;
619 return x - (*iptr);
620}
621
622
623static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
624 LDOUBLE fvalue, int min, int max, int flags)
625{
626 int signvalue = 0;
627 double ufvalue;
628 char iconvert[311];
629 char fconvert[311];
630 int iplace = 0;
631 int fplace = 0;
507 int padlen = 0; /* amount to pad */ 632 int padlen = 0; /* amount to pad */
508 int zpadlen = 0, caps = 0; 633 int zpadlen = 0;
509 long intpart, fracpart; 634 int caps = 0;
510 long double ufvalue; 635 int idx;
636 double intpart;
637 double fracpart;
638 double temp;
511 639
512 /* 640 /*
513 * AIX manpage says the default is 0, but Solaris says the default 641 * AIX manpage says the default is 0, but Solaris says the default
@@ -516,137 +644,159 @@ fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue,
516 if (max < 0) 644 if (max < 0)
517 max = 6; 645 max = 6;
518 646
519 ufvalue = abs_val(fvalue); 647 ufvalue = abs_val (fvalue);
520 648
521 if (fvalue < 0) 649 if (fvalue < 0) {
522 signvalue = '-'; 650 signvalue = '-';
523 else if (flags & DP_F_PLUS) /* Do a sign (+/i) */ 651 } else {
524 signvalue = '+'; 652 if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
525 else if (flags & DP_F_SPACE) 653 signvalue = '+';
526 signvalue = ' '; 654 } else {
655 if (flags & DP_F_SPACE)
656 signvalue = ' ';
657 }
658 }
527 659
528 intpart = ufvalue; 660#if 0
661 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
662#endif
663
664#if 0
665 if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
666#endif
529 667
530 /* 668 /*
531 * Sorry, we only support 9 digits past the decimal because of our 669 * Sorry, we only support 16 digits past the decimal because of our
532 * conversion method 670 * conversion method
533 */ 671 */
534 if (max > 9) 672 if (max > 16)
535 max = 9; 673 max = 16;
536 674
537 /* We "cheat" by converting the fractional part to integer by 675 /* We "cheat" by converting the fractional part to integer by
538 * multiplying by a factor of 10 676 * multiplying by a factor of 10
539 */ 677 */
540 fracpart = round((pow10 (max)) * (ufvalue - intpart));
541 678
542 if (fracpart >= pow10 (max)) { 679 temp = ufvalue;
680 my_modf(temp, &intpart);
681
682 fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
683
684 if (fracpart >= POW10(max)) {
543 intpart++; 685 intpart++;
544 fracpart -= pow10 (max); 686 fracpart -= POW10(max);
545 } 687 }
546 688
547 /* Convert integer part */ 689 /* Convert integer part */
548 do { 690 do {
691 temp = intpart*0.1;
692 my_modf(temp, &intpart);
693 idx = (int) ((temp -intpart +0.05)* 10.0);
694 /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
695 /* printf ("%llf, %f, %x\n", temp, intpart, idx); */
549 iconvert[iplace++] = 696 iconvert[iplace++] =
550 (caps ? "0123456789ABCDEF" : "0123456789abcdef") 697 (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
551 [intpart % 10]; 698 } while (intpart && (iplace < 311));
552 intpart = (intpart / 10); 699 if (iplace == 311) iplace--;
553 } while(intpart && (iplace < 20));
554 if (iplace == 20)
555 iplace--;
556 iconvert[iplace] = 0; 700 iconvert[iplace] = 0;
557 701
558 /* Convert fractional part */ 702 /* Convert fractional part */
559 do { 703 if (fracpart)
560 fconvert[fplace++] = 704 {
561 (caps ? "0123456789ABCDEF" : "0123456789abcdef") 705 do {
562 [fracpart % 10]; 706 temp = fracpart*0.1;
563 fracpart = (fracpart / 10); 707 my_modf(temp, &fracpart);
564 } while(fracpart && (fplace < 20)); 708 idx = (int) ((temp -fracpart +0.05)* 10.0);
565 if (fplace == 20) 709 /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
566 fplace--; 710 /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
711 fconvert[fplace++] =
712 (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
713 } while(fracpart && (fplace < 311));
714 if (fplace == 311) fplace--;
715 }
567 fconvert[fplace] = 0; 716 fconvert[fplace] = 0;
568 717
569 /* -1 for decimal point, another -1 if we are printing a sign */ 718 /* -1 for decimal point, another -1 if we are printing a sign */
570 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 719 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
571 zpadlen = max - fplace; 720 zpadlen = max - fplace;
572 if (zpadlen < 0) 721 if (zpadlen < 0) zpadlen = 0;
573 zpadlen = 0;
574 if (padlen < 0) 722 if (padlen < 0)
575 padlen = 0; 723 padlen = 0;
576 if (flags & DP_F_MINUS) 724 if (flags & DP_F_MINUS)
577 padlen = -padlen; /* Left Justifty */ 725 padlen = -padlen; /* Left Justifty */
578 726
579 if ((flags & DP_F_ZERO) && (padlen > 0)) { 727 if ((flags & DP_F_ZERO) && (padlen > 0)) {
580 if (signvalue) { 728 if (signvalue) {
581 dopr_outch(buffer, currlen, maxlen, signvalue); 729 dopr_outch (buffer, currlen, maxlen, signvalue);
582 --padlen; 730 --padlen;
583 signvalue = 0; 731 signvalue = 0;
584 } 732 }
585 while (padlen > 0) { 733 while (padlen > 0) {
586 dopr_outch(buffer, currlen, maxlen, '0'); 734 dopr_outch (buffer, currlen, maxlen, '0');
587 --padlen; 735 --padlen;
588 } 736 }
589 } 737 }
590 while (padlen > 0) { 738 while (padlen > 0) {
591 dopr_outch(buffer, currlen, maxlen, ' '); 739 dopr_outch (buffer, currlen, maxlen, ' ');
592 --padlen; 740 --padlen;
593 } 741 }
594 if (signvalue) 742 if (signvalue)
595 dopr_outch(buffer, currlen, maxlen, signvalue); 743 dopr_outch (buffer, currlen, maxlen, signvalue);
596 744
597 while (iplace > 0) 745 while (iplace > 0)
598 dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]); 746 dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
747
748#ifdef DEBUG_SNPRINTF
749 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
750#endif
599 751
600 /* 752 /*
601 * Decimal point. This should probably use locale to find the 753 * Decimal point. This should probably use locale to find the correct
602 * correct char to print out. 754 * char to print out.
603 */ 755 */
604 dopr_outch(buffer, currlen, maxlen, '.'); 756 if (max > 0) {
605 757 dopr_outch (buffer, currlen, maxlen, '.');
606 while (fplace > 0) 758
607 dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]); 759 while (zpadlen > 0) {
760 dopr_outch (buffer, currlen, maxlen, '0');
761 --zpadlen;
762 }
608 763
609 while (zpadlen > 0) { 764 while (fplace > 0)
610 dopr_outch(buffer, currlen, maxlen, '0'); 765 dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
611 --zpadlen;
612 } 766 }
613 767
614 while (padlen < 0) { 768 while (padlen < 0) {
615 dopr_outch(buffer, currlen, maxlen, ' '); 769 dopr_outch (buffer, currlen, maxlen, ' ');
616 ++padlen; 770 ++padlen;
617 } 771 }
618} 772}
619 773
620static void 774static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
621dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
622{ 775{
623 if (*currlen < maxlen) 776 if (*currlen < maxlen) {
624 buffer[(*currlen)++] = c; 777 buffer[(*currlen)] = c;
778 }
779 (*currlen)++;
625} 780}
626#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */ 781#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
627 782
628#ifndef HAVE_VSNPRINTF 783#if !defined(HAVE_VSNPRINTF)
629int 784int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
630vsnprintf(char *str, size_t count, const char *fmt, va_list args)
631{ 785{
632 str[0] = 0; 786 return dopr(str, count, fmt, args);
633 dopr(str, count, fmt, args);
634
635 return(strlen(str));
636} 787}
637#endif /* !HAVE_VSNPRINTF */ 788#endif
638 789
639#ifndef HAVE_SNPRINTF 790#if !defined(HAVE_SNPRINTF)
640int 791int snprintf(char *str,size_t count,const char *fmt,...)
641snprintf(char *str,size_t count,const char *fmt,...)
642{ 792{
793 size_t ret;
643 va_list ap; 794 va_list ap;
644 795
645 va_start(ap, fmt); 796 va_start(ap, fmt);
646 (void) vsnprintf(str, count, fmt, ap); 797 ret = vsnprintf(str, count, fmt, ap);
647 va_end(ap); 798 va_end(ap);
648 799 return ret;
649 return(strlen(str));
650} 800}
801#endif
651 802
652#endif /* !HAVE_SNPRINTF */