+#if defined (OS2) && defined (__IBMC__)\r
+/*\r
+ * Copyright Patrick Powell 1995\r
+ * This code is based on code written by Patrick Powell (papowell@astart.com)\r
+ * It may be used for any purpose as long as this notice remains intact\r
+ * on all source code distributions\r
+ */\r
+\r
+/**************************************************************\r
+ * Original:\r
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995\r
+ * A bombproof version of doprnt (dopr) included.\r
+ * Sigh. This sort of thing is always nasty do deal with. Note that\r
+ * the version here does not include floating point...\r
+ *\r
+ * snprintf() is used instead of sprintf() as it does limit checks\r
+ * for string length. This covers a nasty loophole.\r
+ *\r
+ * The other functions are there to prevent NULL pointers from\r
+ * causing nast effects.\r
+ *\r
+ * More Recently:\r
+ * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43\r
+ * This was ugly. It is still ugly. I opted out of floating point\r
+ * numbers, but the formatter understands just about everything\r
+ * from the normal C string format, at least as far as I can tell from\r
+ * the Solaris 2.5 printf(3S) man page.\r
+ *\r
+ * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1\r
+ * Ok, added some minimal floating point support, which means this\r
+ * probably requires libm on most operating systems. Don't yet\r
+ * support the exponent (e,E) and sigfig (g,G). Also, fmtint()\r
+ * was pretty badly broken, it just wasn't being exercised in ways\r
+ * which showed it, so that's been fixed. Also, formated the code\r
+ * to mutt conventions, and removed dead code left over from the\r
+ * original. Also, there is now a builtin-test, just compile with:\r
+ * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm\r
+ * and run snprintf for results.\r
+ *\r
+ * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i\r
+ * The PGP code was using unsigned hexadecimal formats.\r
+ * Unfortunately, unsigned formats simply didn't work.\r
+ *\r
+ * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8\r
+ * The original code assumed that both snprintf() and vsnprintf() were\r
+ * missing. Some systems only have snprintf() but not vsnprintf(), so\r
+ * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.\r
+ *\r
+ * Andrew Tridgell (tridge@samba.org) Oct 1998\r
+ * fixed handling of %.0f\r
+ * added test for HAVE_LONG_DOUBLE\r
+ *\r
+ * tridge@samba.org, idra@samba.org, April 2001\r
+ * got rid of fcvt code (twas buggy and made testing harder)\r
+ * added C99 semantics\r
+ *\r
+ **************************************************************/\r
+\r
+#ifndef NO_CONFIG_H /* for some tests */\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_STRING_H\r
+#include <string.h>\r
+#endif\r
+\r
+#ifdef HAVE_STRINGS_H\r
+#include <strings.h>\r
+#endif\r
+#ifdef HAVE_CTYPE_H\r
+#include <ctype.h>\r
+#endif\r
+#include <sys/types.h>\r
+#include <stdarg.h>\r
+#ifdef HAVE_STDLIB_H\r
+#include <stdlib.h>\r
+#endif\r
+\r
+#if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)\r
+/* only include stdio.h if we are not re-defining snprintf or vsnprintf */\r
+#include <stdio.h>\r
+/* make the compiler happy with an empty file */\r
+void dummy_snprintf(void) {}\r
+#else\r
+\r
+#ifdef HAVE_LONG_DOUBLE\r
+#define LDOUBLE long double\r
+#else\r
+#define LDOUBLE double\r
+#endif\r
+\r
+#ifdef HAVE_LONG_LONG\r
+#define LLONG long long\r
+#else\r
+#define LLONG long\r
+#endif\r
+\r
+static size_t dopr(char *buffer, size_t maxlen, const char *format,\r
+ va_list args);\r
+static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,\r
+ char *value, int flags, int min, int max);\r
+static void fmtint(char *buffer, size_t *currlen, size_t maxlen,\r
+ long value, int base, int min, int max, int flags);\r
+static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,\r
+ LDOUBLE fvalue, int min, int max, int flags);\r
+static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);\r
+\r
+/*\r
+ * dopr(): poor man's version of doprintf\r
+ */\r
+\r
+/* format read states */\r
+#define DP_S_DEFAULT 0\r
+#define DP_S_FLAGS 1\r
+#define DP_S_MIN 2\r
+#define DP_S_DOT 3\r
+#define DP_S_MAX 4\r
+#define DP_S_MOD 5\r
+#define DP_S_CONV 6\r
+#define DP_S_DONE 7\r
+\r
+/* format flags - Bits */\r
+#define DP_F_MINUS (1 << 0)\r
+#define DP_F_PLUS (1 << 1)\r
+#define DP_F_SPACE (1 << 2)\r
+#define DP_F_NUM (1 << 3)\r
+#define DP_F_ZERO (1 << 4)\r
+#define DP_F_UP (1 << 5)\r
+#define DP_F_UNSIGNED (1 << 6)\r
+\r
+/* Conversion Flags */\r
+#define DP_C_SHORT 1\r
+#define DP_C_LONG 2\r
+#define DP_C_LDOUBLE 3\r
+#define DP_C_LLONG 4\r
+\r
+#define char_to_int(p) ((p)- '0')\r
+#ifndef MAX\r
+#define MAX(p,q) (((p) >= (q)) ? (p) : (q))\r
+#endif\r
+\r
+static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args)\r
+{\r
+ char ch;\r
+ LLONG value;\r
+ LDOUBLE fvalue;\r
+ char *strvalue;\r
+ int min;\r
+ int max;\r
+ int state;\r
+ int flags;\r
+ int cflags;\r
+ size_t currlen;\r
+ \r
+ state = DP_S_DEFAULT;\r
+ currlen = flags = cflags = min = 0;\r
+ max = -1;\r
+ ch = *format++;\r
+ \r
+ while (state != DP_S_DONE) {\r
+ if (ch == '\0')\r
+ state = DP_S_DONE;\r
+\r
+ switch(state) {\r
+ case DP_S_DEFAULT:\r
+ if (ch == '%')\r
+ state = DP_S_FLAGS;\r
+ else\r
+ dopr_outch (buffer, &currlen, maxlen, ch);\r
+ ch = *format++;\r
+ break;\r
+ case DP_S_FLAGS:\r
+ switch (ch) {\r
+ case '-':\r
+ flags |= DP_F_MINUS;\r
+ ch = *format++;\r
+ break;\r
+ case '+':\r
+ flags |= DP_F_PLUS;\r
+ ch = *format++;\r
+ break;\r
+ case ' ':\r
+ flags |= DP_F_SPACE;\r
+ ch = *format++;\r
+ break;\r
+ case '#':\r
+ flags |= DP_F_NUM;\r
+ ch = *format++;\r
+ break;\r
+ case '0':\r
+ flags |= DP_F_ZERO;\r
+ ch = *format++;\r
+ break;\r
+ default:\r
+ state = DP_S_MIN;\r
+ break;\r
+ }\r
+ break;\r
+ case DP_S_MIN:\r
+ if (isdigit((unsigned char)ch)) {\r
+ min = 10*min + char_to_int (ch);\r
+ ch = *format++;\r
+ } else if (ch == '*') {\r
+ min = va_arg (args, int);\r
+ ch = *format++;\r
+ state = DP_S_DOT;\r
+ } else {\r
+ state = DP_S_DOT;\r
+ }\r
+ break;\r
+ case DP_S_DOT:\r
+ if (ch == '.') {\r
+ state = DP_S_MAX;\r
+ ch = *format++;\r
+ } else {\r
+ state = DP_S_MOD;\r
+ }\r
+ break;\r
+ case DP_S_MAX:\r
+ if (isdigit((unsigned char)ch)) {\r
+ if (max < 0)\r
+ max = 0;\r
+ max = 10*max + char_to_int (ch);\r
+ ch = *format++;\r
+ } else if (ch == '*') {\r
+ max = va_arg (args, int);\r
+ ch = *format++;\r
+ state = DP_S_MOD;\r
+ } else {\r
+ state = DP_S_MOD;\r
+ }\r
+ break;\r
+ case DP_S_MOD:\r
+ switch (ch) {\r
+ case 'h':\r
+ cflags = DP_C_SHORT;\r
+ ch = *format++;\r
+ break;\r
+ case 'l':\r
+ cflags = DP_C_LONG;\r
+ ch = *format++;\r
+ if (ch == 'l') { /* It's a long long */\r
+ cflags = DP_C_LLONG;\r
+ ch = *format++;\r
+ }\r
+ break;\r
+ case 'L':\r
+ cflags = DP_C_LDOUBLE;\r
+ ch = *format++;\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ state = DP_S_CONV;\r
+ break;\r
+ case DP_S_CONV:\r
+ switch (ch) {\r
+ case 'd':\r
+ case 'i':\r
+ if (cflags == DP_C_SHORT)\r
+ value = va_arg (args, int);\r
+ else if (cflags == DP_C_LONG)\r
+ value = va_arg (args, long int);\r
+ else if (cflags == DP_C_LLONG)\r
+ value = va_arg (args, LLONG);\r
+ else\r
+ value = va_arg (args, int);\r
+ fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);\r
+ break;\r
+ case 'o':\r
+ flags |= DP_F_UNSIGNED;\r
+ if (cflags == DP_C_SHORT)\r
+ value = va_arg (args, unsigned int);\r
+ else if (cflags == DP_C_LONG)\r
+ value = (long)va_arg (args, unsigned long int);\r
+ else if (cflags == DP_C_LLONG)\r
+ value = (long)va_arg (args, unsigned LLONG);\r
+ else\r
+ value = (long)va_arg (args, unsigned int);\r
+ fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);\r
+ break;\r
+ case 'u':\r
+ flags |= DP_F_UNSIGNED;\r
+ if (cflags == DP_C_SHORT)\r
+ value = va_arg (args, unsigned int);\r
+ else if (cflags == DP_C_LONG)\r
+ value = (long)va_arg (args, unsigned long int);\r
+ else if (cflags == DP_C_LLONG)\r
+ value = (LLONG)va_arg (args, unsigned LLONG);\r
+ else\r
+ value = (long)va_arg (args, unsigned int);\r
+ fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);\r
+ break;\r
+ case 'X':\r
+ flags |= DP_F_UP;\r
+ case 'x':\r
+ flags |= DP_F_UNSIGNED;\r
+ if (cflags == DP_C_SHORT)\r
+ value = va_arg (args, unsigned int);\r
+ else if (cflags == DP_C_LONG)\r
+ value = (long)va_arg (args, unsigned long int);\r
+ else if (cflags == DP_C_LLONG)\r
+ value = (LLONG)va_arg (args, unsigned LLONG);\r
+ else\r
+ value = (long)va_arg (args, unsigned int);\r
+ fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);\r
+ break;\r
+ case 'f':\r
+ if (cflags == DP_C_LDOUBLE)\r
+ fvalue = va_arg (args, LDOUBLE);\r
+ else\r
+ fvalue = va_arg (args, double);\r
+ /* um, floating point? */\r
+ fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);\r
+ break;\r
+ case 'E':\r
+ flags |= DP_F_UP;\r
+ case 'e':\r
+ if (cflags == DP_C_LDOUBLE)\r
+ fvalue = va_arg (args, LDOUBLE);\r
+ else\r
+ fvalue = va_arg (args, double);\r
+ break;\r
+ case 'G':\r
+ flags |= DP_F_UP;\r
+ case 'g':\r
+ if (cflags == DP_C_LDOUBLE)\r
+ fvalue = va_arg (args, LDOUBLE);\r
+ else\r
+ fvalue = va_arg (args, double);\r
+ break;\r
+ case 'c':\r
+ dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));\r
+ break;\r
+ case 's':\r
+ strvalue = va_arg (args, char *);\r
+ if (max == -1) {\r
+ max = strlen(strvalue);\r
+ }\r
+ if (min > 0 && max >= 0 && min > max) max = min;\r
+ fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);\r
+ break;\r
+ case 'p':\r
+ strvalue = va_arg (args, void *);\r
+ fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);\r
+ break;\r
+ case 'n':\r
+ if (cflags == DP_C_SHORT) {\r
+ short int *num;\r
+ num = va_arg (args, short int *);\r
+ *num = currlen;\r
+ } else if (cflags == DP_C_LONG) {\r
+ long int *num;\r
+ num = va_arg (args, long int *);\r
+ *num = (long int)currlen;\r
+ } else if (cflags == DP_C_LLONG) {\r
+ LLONG *num;\r
+ num = va_arg (args, LLONG *);\r
+ *num = (LLONG)currlen;\r
+ } else {\r
+ int *num;\r
+ num = va_arg (args, int *);\r
+ *num = currlen;\r
+ }\r
+ break;\r
+ case '%':\r
+ dopr_outch (buffer, &currlen, maxlen, ch);\r
+ break;\r
+ case 'w':\r
+ /* not supported yet, treat as next char */\r
+ ch = *format++;\r
+ break;\r
+ default:\r
+ /* Unknown, skip */\r
+ break;\r
+ }\r
+ ch = *format++;\r
+ state = DP_S_DEFAULT;\r
+ flags = cflags = min = 0;\r
+ max = -1;\r
+ break;\r
+ case DP_S_DONE:\r
+ break;\r
+ default:\r
+ /* hmm? */\r
+ break; /* some picky compilers need this */\r
+ }\r
+ }\r
+ if (maxlen != 0) {\r
+ if (currlen < maxlen - 1)\r
+ buffer[currlen] = '\0';\r
+ else if (maxlen > 0)\r
+ buffer[maxlen - 1] = '\0';\r
+ }\r
+ \r
+ return currlen;\r
+}\r
+\r
+static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,\r
+ char *value, int flags, int min, int max)\r
+{\r
+ int padlen, strln; /* amount to pad */\r
+ int cnt = 0;\r
+\r
+#ifdef DEBUG_SNPRINTF\r
+ printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);\r
+#endif\r
+ if (value == 0) {\r
+ value = "<NULL>";\r
+ }\r
+\r
+ for (strln = 0; value[strln]; ++strln); /* strlen */\r
+ padlen = min - strln;\r
+ if (padlen < 0)\r
+ padlen = 0;\r
+ if (flags & DP_F_MINUS)\r
+ padlen = -padlen; /* Left Justify */\r
+ \r
+ while ((padlen > 0) && (cnt < max)) {\r
+ dopr_outch (buffer, currlen, maxlen, ' ');\r
+ --padlen;\r
+ ++cnt;\r
+ }\r
+ while (*value && (cnt < max)) {\r
+ dopr_outch (buffer, currlen, maxlen, *value++);\r
+ ++cnt;\r
+ }\r
+ while ((padlen < 0) && (cnt < max)) {\r
+ dopr_outch (buffer, currlen, maxlen, ' ');\r
+ ++padlen;\r
+ ++cnt;\r
+ }\r
+}\r
+\r
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */\r
+\r
+static void fmtint(char *buffer, size_t *currlen, size_t maxlen,\r
+ long value, int base, int min, int max, int flags)\r
+{\r
+ int signvalue = 0;\r
+ unsigned long uvalue;\r
+ char convert[20];\r
+ int place = 0;\r
+ int spadlen = 0; /* amount to space pad */\r
+ int zpadlen = 0; /* amount to zero pad */\r
+ int caps = 0;\r
+ \r
+ if (max < 0)\r
+ max = 0;\r
+ \r
+ uvalue = value;\r
+ \r
+ if(!(flags & DP_F_UNSIGNED)) {\r
+ if( value < 0 ) {\r
+ signvalue = '-';\r
+ uvalue = -value;\r
+ } else {\r
+ if (flags & DP_F_PLUS) /* Do a sign (+/i) */\r
+ signvalue = '+';\r
+ else if (flags & DP_F_SPACE)\r
+ signvalue = ' ';\r
+ }\r
+ }\r
+ \r
+ if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */\r
+\r
+ do {\r
+ convert[place++] =\r
+ (caps? "0123456789ABCDEF":"0123456789abcdef")\r
+ [uvalue % (unsigned)base ];\r
+ uvalue = (uvalue / (unsigned)base );\r
+ } while(uvalue && (place < 20));\r
+ if (place == 20) place--;\r
+ convert[place] = 0;\r
+\r
+ zpadlen = max - place;\r
+ spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);\r
+ if (zpadlen < 0) zpadlen = 0;\r
+ if (spadlen < 0) spadlen = 0;\r
+ if (flags & DP_F_ZERO) {\r
+ zpadlen = MAX(zpadlen, spadlen);\r
+ spadlen = 0;\r
+ }\r
+ if (flags & DP_F_MINUS)\r
+ spadlen = -spadlen; /* Left Justifty */\r
+\r
+#ifdef DEBUG_SNPRINTF\r
+ printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",\r
+ zpadlen, spadlen, min, max, place);\r
+#endif\r
+\r
+ /* Spaces */\r
+ while (spadlen > 0) {\r
+ dopr_outch (buffer, currlen, maxlen, ' ');\r
+ --spadlen;\r
+ }\r
+\r
+ /* Sign */\r
+ if (signvalue)\r
+ dopr_outch (buffer, currlen, maxlen, signvalue);\r
+\r
+ /* Zeros */\r
+ if (zpadlen > 0) {\r
+ while (zpadlen > 0) {\r
+ dopr_outch (buffer, currlen, maxlen, '0');\r
+ --zpadlen;\r
+ }\r
+ }\r
+\r
+ /* Digits */\r
+ while (place > 0)\r
+ dopr_outch (buffer, currlen, maxlen, convert[--place]);\r
+ \r
+ /* Left Justified spaces */\r
+ while (spadlen < 0) {\r
+ dopr_outch (buffer, currlen, maxlen, ' ');\r
+ ++spadlen;\r
+ }\r
+}\r
+\r
+static LDOUBLE abs_val(LDOUBLE value)\r
+{\r
+ LDOUBLE result = value;\r
+\r
+ if (value < 0)\r
+ result = -value;\r
+ \r
+ return result;\r
+}\r
+\r
+static LDOUBLE POW10(int exp)\r
+{\r
+ LDOUBLE result = 1;\r
+ \r
+ while (exp) {\r
+ result *= 10;\r
+ exp--;\r
+ }\r
+ \r
+ return result;\r
+}\r
+\r
+static LLONG ROUND(LDOUBLE value)\r
+{\r
+ LLONG intpart;\r
+\r
+ intpart = (LLONG)value;\r
+ value = value - intpart;\r
+ if (value >= 0.5) intpart++;\r
+ \r
+ return intpart;\r
+}\r
+\r
+/* a replacement for modf that doesn't need the math library. Should\r
+ be portable, but slow */\r
+static double my_modf(double x0, double *iptr)\r
+{\r
+ int i;\r
+ long l;\r
+ double x = x0;\r
+ double f = 1.0;\r
+\r
+ for (i=0;i<100;i++) {\r
+ l = (long)x;\r
+ if (l <= (x+1) && l >= (x-1)) break;\r
+ x *= 0.1;\r
+ f *= 10.0;\r
+ }\r
+\r
+ if (i == 100) {\r
+ /* yikes! the number is beyond what we can handle. What do we do? */\r
+ (*iptr) = 0;\r
+ return 0;\r
+ }\r
+\r
+ if (i != 0) {\r
+ double i2;\r
+ double ret;\r
+\r
+ ret = my_modf(x0-l*f, &i2);\r
+ (*iptr) = l*f + i2;\r
+ return ret;\r
+ }\r
+\r
+ (*iptr) = l;\r
+ return x - (*iptr);\r
+}\r
+\r
+\r
+static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,\r
+ LDOUBLE fvalue, int min, int max, int flags)\r
+{\r
+ int signvalue = 0;\r
+ double ufvalue;\r
+ char iconvert[311];\r
+ char fconvert[311];\r
+ int iplace = 0;\r
+ int fplace = 0;\r
+ int padlen = 0; /* amount to pad */\r
+ int zpadlen = 0;\r
+ int caps = 0;\r
+ int index;\r
+ double intpart;\r
+ double fracpart;\r
+ double temp;\r
+ \r
+ /*\r
+ * AIX manpage says the default is 0, but Solaris says the default\r
+ * is 6, and sprintf on AIX defaults to 6\r
+ */\r
+ if (max < 0)\r
+ max = 6;\r
+\r
+ ufvalue = abs_val (fvalue);\r
+\r
+ if (fvalue < 0) {\r
+ signvalue = '-';\r
+ } else {\r
+ if (flags & DP_F_PLUS) { /* Do a sign (+/i) */\r
+ signvalue = '+';\r
+ } else {\r
+ if (flags & DP_F_SPACE)\r
+ signvalue = ' ';\r
+ }\r
+ }\r
+\r
+#if 0\r
+ if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */\r
+#endif\r
+\r
+#if 0\r
+ if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */\r
+#endif\r
+\r
+ /*\r
+ * Sorry, we only support 16 digits past the decimal because of our\r
+ * conversion method\r
+ */\r
+ if (max > 16)\r
+ max = 16;\r
+\r
+ /* We "cheat" by converting the fractional part to integer by\r
+ * multiplying by a factor of 10\r
+ */\r
+\r
+ temp = ufvalue;\r
+ my_modf(temp, &intpart);\r
+\r
+ fracpart = ROUND((POW10(max)) * (ufvalue - intpart));\r
+ \r
+ if (fracpart >= POW10(max)) {\r
+ intpart++;\r
+ fracpart -= POW10(max);\r
+ }\r
+\r
+\r
+ /* Convert integer part */\r
+ do {\r
+ temp = intpart;\r
+ my_modf(intpart*0.1, &intpart);\r
+ temp = temp*0.1;\r
+ index = (int) ((temp -intpart +0.05)* 10.0);\r
+ /* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */\r
+ /* printf ("%llf, %f, %x\n", temp, intpart, index); */\r
+ iconvert[iplace++] =\r
+ (caps? "0123456789ABCDEF":"0123456789abcdef")[index];\r
+ } while (intpart && (iplace < 311));\r
+ if (iplace == 311) iplace--;\r
+ iconvert[iplace] = 0;\r
+\r
+ /* Convert fractional part */\r
+ if (fracpart)\r
+ {\r
+ do {\r
+ temp = fracpart;\r
+ my_modf(fracpart*0.1, &fracpart);\r
+ temp = temp*0.1;\r
+ index = (int) ((temp -fracpart +0.05)* 10.0);\r
+ /* index = (int) ((((temp/10) -fracpart) +0.05) *10); */\r
+ /* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */\r
+ fconvert[fplace++] =\r
+ (caps? "0123456789ABCDEF":"0123456789abcdef")[index];\r
+ } while(fracpart && (fplace < 311));\r
+ if (fplace == 311) fplace--;\r
+ }\r
+ fconvert[fplace] = 0;\r
+ \r
+ /* -1 for decimal point, another -1 if we are printing a sign */\r
+ padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);\r
+ zpadlen = max - fplace;\r
+ if (zpadlen < 0) zpadlen = 0;\r
+ if (padlen < 0)\r
+ padlen = 0;\r
+ if (flags & DP_F_MINUS)\r
+ padlen = -padlen; /* Left Justifty */\r
+ \r
+ if ((flags & DP_F_ZERO) && (padlen > 0)) {\r
+ if (signvalue) {\r
+ dopr_outch (buffer, currlen, maxlen, signvalue);\r
+ --padlen;\r
+ signvalue = 0;\r
+ }\r
+ while (padlen > 0) {\r
+ dopr_outch (buffer, currlen, maxlen, '0');\r
+ --padlen;\r
+ }\r
+ }\r
+ while (padlen > 0) {\r
+ dopr_outch (buffer, currlen, maxlen, ' ');\r
+ --padlen;\r
+ }\r
+ if (signvalue)\r
+ dopr_outch (buffer, currlen, maxlen, signvalue);\r
+ \r
+ while (iplace > 0)\r
+ dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);\r
+\r
+#ifdef DEBUG_SNPRINTF\r
+ printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);\r
+#endif\r
+\r
+ /*\r
+ * Decimal point. This should probably use locale to find the correct\r
+ * char to print out.\r
+ */\r
+ if (max > 0) {\r
+ dopr_outch (buffer, currlen, maxlen, '.');\r
+ \r
+ while (fplace > 0)\r
+ dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);\r
+ }\r
+ \r
+ while (zpadlen > 0) {\r
+ dopr_outch (buffer, currlen, maxlen, '0');\r
+ --zpadlen;\r
+ }\r
+\r
+ while (padlen < 0) {\r
+ dopr_outch (buffer, currlen, maxlen, ' ');\r
+ ++padlen;\r
+ }\r
+}\r
+\r
+static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)\r
+{\r
+ if (*currlen < maxlen) {\r
+ buffer[(*currlen)] = c;\r
+ }\r
+ (*currlen)++;\r
+}\r
+\r
+#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)\r
+int vsnprintf (char *str, size_t count, const char *fmt, va_list args)\r
+{\r
+ return dopr(str, count, fmt, args);\r
+}\r
+#endif\r
+\r
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)\r
+int snprintf(char *str,size_t count,const char *fmt,...)\r
+{\r
+ size_t ret;\r
+ va_list ap;\r
+ \r
+ va_start(ap, fmt);\r
+ ret = vsnprintf(str, count, fmt, ap);\r
+ va_end(ap);\r
+ return ret;\r
+}\r
+#endif\r
+\r
+#endif\r
+\r
+#ifndef HAVE_VASPRINTF\r
+int vasprintf(char **ptr, const char *format, va_list ap)\r
+{\r
+ int ret;\r
+ \r
+ ret = vsnprintf(NULL, 0, format, ap);\r
+ if (ret <= 0) return ret;\r
+\r
+ (*ptr) = (char *)malloc(ret+1);\r
+ if (!*ptr) return -1;\r
+ ret = vsnprintf(*ptr, ret+1, format, ap);\r
+\r
+ return ret;\r
+}\r
+#endif\r
+\r
+\r
+#ifndef HAVE_ASPRINTF\r
+int asprintf(char **ptr, const char *format, ...)\r
+{\r
+ va_list ap;\r
+ int ret;\r
+ \r
+ va_start(ap, format);\r
+ ret = vasprintf(ptr, format, ap);\r
+ va_end(ap);\r
+\r
+ return ret;\r
+}\r
+#endif\r
+\r
+#ifdef TEST_SNPRINTF\r
+\r
+int sprintf(char *str,const char *fmt,...);\r
+\r
+int main (void)\r
+{\r
+ char buf1[1024];\r
+ char buf2[1024];\r
+ char *fp_fmt[] = {\r
+ "%1.1f",\r
+ "%-1.5f",\r
+ "%1.5f",\r
+ "%123.9f",\r
+ "%10.5f",\r
+ "% 10.5f",\r
+ "%+22.9f",\r
+ "%+4.9f",\r
+ "%01.3f",\r
+ "%4f",\r
+ "%3.1f",\r
+ "%3.2f",\r
+ "%.0f",\r
+ "%f",\r
+ "-16.16f",\r
+ NULL\r
+ };\r
+ double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,\r
+ 0.9996, 1.996, 4.136, 0};\r
+ char *int_fmt[] = {\r
+ "%-1.5d",\r
+ "%1.5d",\r
+ "%123.9d",\r
+ "%5.5d",\r
+ "%10.5d",\r
+ "% 10.5d",\r
+ "%+22.33d",\r
+ "%01.3d",\r
+ "%4d",\r
+ "%d",\r
+ NULL\r
+ };\r
+ long int_nums[] = { -1, 134, 91340, 341, 0203, 0};\r
+ char *str_fmt[] = {\r
+ "10.5s",\r
+ "5.10s",\r
+ "10.1s",\r
+ "0.10s",\r
+ "10.0s",\r
+ "1.10s",\r
+ "%s",\r
+ "%.1s",\r
+ "%.10s",\r
+ "%10s",\r
+ NULL\r
+ };\r
+ char *str_vals[] = {"hello", "a", "", "a longer string", NULL};\r
+ int x, y;\r
+ int fail = 0;\r
+ int num = 0;\r
+\r
+ printf ("Testing snprintf format codes against system sprintf...\n");\r
+\r
+ for (x = 0; fp_fmt[x] ; x++) {\r
+ for (y = 0; fp_nums[y] != 0 ; y++) {\r
+ int l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]);\r
+ int l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);\r
+ sprintf (buf2, fp_fmt[x], fp_nums[y]);\r
+ if (strcmp (buf1, buf2)) {\r
+ printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",\r
+ fp_fmt[x], buf1, buf2);\r
+ fail++;\r
+ }\r
+ if (l1 != l2) {\r
+ printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, fp_fmt[x]);\r
+ fail++;\r
+ }\r
+ num++;\r
+ }\r
+ }\r
+\r
+ for (x = 0; int_fmt[x] ; x++) {\r
+ for (y = 0; int_nums[y] != 0 ; y++) {\r
+ int l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]);\r
+ int l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);\r
+ sprintf (buf2, int_fmt[x], int_nums[y]);\r
+ if (strcmp (buf1, buf2)) {\r
+ printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",\r
+ int_fmt[x], buf1, buf2);\r
+ fail++;\r
+ }\r
+ if (l1 != l2) {\r
+ printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, int_fmt[x]);\r
+ fail++;\r
+ }\r
+ num++;\r
+ }\r
+ }\r
+\r
+ for (x = 0; str_fmt[x] ; x++) {\r
+ for (y = 0; str_vals[y] != 0 ; y++) {\r
+ int l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]);\r
+ int l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);\r
+ sprintf (buf2, str_fmt[x], str_vals[y]);\r
+ if (strcmp (buf1, buf2)) {\r
+ printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",\r
+ str_fmt[x], buf1, buf2);\r
+ fail++;\r
+ }\r
+ if (l1 != l2) {\r
+ printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, str_fmt[x]);\r
+ fail++;\r
+ }\r
+ num++;\r
+ }\r
+ }\r
+\r
+ printf ("%d tests failed out of %d.\n", fail, num);\r
+\r
+ printf("seeing how many digits we support\n");\r
+ {\r
+ double v0 = 0.12345678901234567890123456789012345678901;\r
+ for (x=0; x<100; x++) {\r
+ snprintf(buf1, sizeof(buf1), "%1.1f", v0*pow(10, x));\r
+ sprintf(buf2, "%1.1f", v0*pow(10, x));\r
+ if (strcmp(buf1, buf2)) {\r
+ printf("we seem to support %d digits\n", x-1);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ return 0;\r
+}\r
+#endif /* SNPRINTF_TEST */\r
+\r
+#endif /* OS2 && __IBMC__ */\r