Date: Tue, 01 Apr 2003 16:43:23 +0100 From: "Richard Dawe" Sender: rich AT phekda DOT freeserve DOT co DOT uk To: djgpp-workers AT delorie DOT com X-Mailer: Emacs 21.3.50 (via feedmail 8.3.emacs20_6 I) and Blat ver 1.8.6 Subject: *printf and nan(0x[0-9a-f]*) - work-in-progress [PATCH] Message-Id: Reply-To: djgpp-workers AT delorie DOT com Hello. Below is my work-in-progress for *printf and supporting nan(0x[0-9a-f]*). This is just for information - don't apply this! Bye, Rich =] Index: src/libc/ansi/stdio/doprnt.c =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/ansi/stdio/doprnt.c,v retrieving revision 1.14 diff -p -c -3 -r1.14 doprnt.c *** src/libc/ansi/stdio/doprnt.c 24 Jan 2003 18:53:33 -0000 1.14 --- src/libc/ansi/stdio/doprnt.c 1 Apr 2003 15:37:44 -0000 *************** *** 17,22 **** --- 17,30 ---- #include #include #include + #include + + struct IEEExp { + unsigned manl:32; + unsigned manh:32; + unsigned exp:15; + unsigned sign:1; + }; static char decimal = '.'; *************** static char decimal = '.'; *** 40,47 **** flags&CHARINT ? (char basetype)va_arg(argp, int) : \ (basetype)va_arg(argp, int) - static int nan_p = 0; - static __inline__ int todigit(char c) { if (c<='0') return 0; --- 48,53 ---- *************** static char *roundl(long double fract, i *** 72,82 **** char ch, char *signp); static char *exponentl(char *p, int expv, unsigned char fmtch); #ifdef __GO32__ ! static int isspeciall(long double d, char *bufp); #endif static char NULL_REP[] = "(null)"; ! static char UNNORMAL_REP[] = "Unnormal"; int _doprnt(const char *fmt0, va_list argp, FILE *fp) --- 78,91 ---- char ch, char *signp); static char *exponentl(char *p, int expv, unsigned char fmtch); #ifdef __GO32__ ! static int isspeciall(long double d, const int was_double, const int do_upper, ! char *signp, char *startp, char *endp); #endif static char NULL_REP[] = "(null)"; ! static const char UNNORMAL_REP[] = "Unnormal"; ! static const char HEX_LOWER_DIGITS[] = "0123456789abcdef"; ! static const char HEX_UPPER_DIGITS[] = "0123456789ABCDEF"; int _doprnt(const char *fmt0, va_list argp, FILE *fp) *************** _doprnt(const char *fmt0, va_list argp, *** 115,121 **** return (EOF); fmt = fmt0; ! digs = "0123456789abcdef"; for (cnt = 0;; ++fmt) { while ((ch = *fmt) && ch != '%') --- 124,130 ---- return (EOF); fmt = fmt0; ! digs = HEX_LOWER_DIGITS; for (cnt = 0;; ++fmt) { while ((ch = *fmt) && ch != '%') *************** _doprnt(const char *fmt0, va_list argp, *** 239,244 **** --- 248,254 ---- case 'e': case 'E': case 'f': + case 'F': case 'g': case 'G': if (flags & LONGDBL) *************** _doprnt(const char *fmt0, va_list argp, *** 274,285 **** } else { ! struct IEEExp { ! unsigned manl:32; ! unsigned manh:32; ! unsigned exp:15; ! unsigned sign:1; ! } ip = *(struct IEEExp *)&_ldouble; if (ip.sign) neg_ldouble = 1; --- 284,290 ---- } else { ! struct IEEExp ip = *(struct IEEExp *)&_ldouble; if (ip.sign) neg_ldouble = 1; *************** _doprnt(const char *fmt0, va_list argp, *** 301,309 **** * will be shown, and we also print a sign for a NaN. In * other words, "%+f" might print -0.000000, +NaN and -NaN. */ ! if (softsign || (sign == '+' && (neg_ldouble || nan_p == -1))) sign = '-'; - nan_p = 0; t = *buf ? buf : buf + 1; goto pforw; case 'n': --- 306,313 ---- * will be shown, and we also print a sign for a NaN. In * other words, "%+f" might print -0.000000, +NaN and -NaN. */ ! if (softsign || (sign == '+' && neg_ldouble)) sign = '-'; t = *buf ? buf : buf + 1; goto pforw; case 'n': *************** _doprnt(const char *fmt0, va_list argp, *** 370,376 **** base = 10; goto nosign; case 'X': ! digs = "0123456789ABCDEF"; /* FALLTHROUGH */ case 'x': ARG(unsigned); --- 374,380 ---- base = 10; goto nosign; case 'X': ! digs = HEX_UPPER_DIGITS; /* FALLTHROUGH */ case 'x': ARG(unsigned); *************** _doprnt(const char *fmt0, va_list argp, *** 419,425 **** *--t = '0'; /* octal leading 0 */ } ! digs = "0123456789abcdef"; size = buf + BUF - t; pforw: --- 423,429 ---- *--t = '0'; /* octal leading 0 */ } ! digs = HEX_LOWER_DIGITS; size = buf + BUF - t; pforw: *************** cvtl(long double number, int prec, int f *** 527,533 **** int doingzero=0; /* We're displaying 0.0 */ long double integer, tmp; ! if ((expcnt = isspeciall(number, startp))) return(expcnt); dotrim = expcnt = gformat = 0; --- 531,539 ---- int doingzero=0; /* We're displaying 0.0 */ long double integer, tmp; ! if ((expcnt = isspeciall(number, ! !(flags & LONGDBL) /* double -> long double? */, ! isupper(fmtch), signp, startp, endp))) return(expcnt); dotrim = expcnt = gformat = 0; *************** cvtl(long double number, int prec, int f *** 595,600 **** --- 601,607 ---- switch(fmtch) { case 'f': + case 'F': /* reverse integer into beginning of buffer */ if (expcnt) for (; ++p < endp; *t++ = *p); *************** exponentl(char *p, int expv, unsigned ch *** 890,924 **** } static int ! isspeciall(long double d, char *bufp) { ! struct IEEExp { ! unsigned manl:32; ! unsigned manh:32; ! unsigned exp:15; ! unsigned sign:1; ! } *ip = (struct IEEExp *)&d; ! nan_p = 0; /* don't assume the static is 0 (emacs) */ /* Unnormals: the MSB of mantissa is non-zero, but the exponent is not zero either. */ ! if ((ip->manh & 0x80000000U) == 0 && ip->exp != 0) { ! if (ip->sign) *bufp++ = '-'; strcpy(bufp, UNNORMAL_REP); ! return strlen(bufp) + ip->sign; } ! if (ip->exp != 0x7fff) return(0); ! if ((ip->manh & 0x7fffffff) || ip->manl) ! { ! strcpy(bufp, "NaN"); ! nan_p = ip->sign ? -1 : 1; /* kludge: we don't need the sign, it's ! not nice, but it should work */ ! } else ! (void)strcpy(bufp, "Inf"); ! return(3); } --- 897,1043 ---- } static int ! hexify (unsigned t, char **p, int leading_zero, const char *digs) ! { ! int i = 7; ! ! /* Skip leading zeroes, if any. */ ! if (leading_zero) ! { ! for (; i >= 0; i--) ! { ! if ((t >> (i * 4)) & 0xf) ! break; ! } ! } ! ! if (i >= 0) ! leading_zero = 0; ! ! for (; i >= 0; i--) ! { ! **p = digs[(t >> (i * 4)) & 0xf]; ! (*p)++; ! } ! ! return(leading_zero); ! } ! ! static void ! addnan (const long double ld, const struct IEEExp ip, ! const int was_double /* was double converted to a long double? */, ! const int do_upper /* inf & nan should be upper-case? */, ! char *startp, char *endp) ! { ! const char *digs = NULL; ! ! /* For converting the long double back to a double, if necessary. */ ! double d; ! double_t ip_d; ! ! /* For checking whether we have one of the NaN values that we don't ! * expand to nan(0x[0-9a-f]*). */ ! long double ld_cast_nan = NAN; ! long_double_t ip_ld_cast_nan; ! ! double_t ip_d_nan = { 0xffffffffU, 0xfffffU, 0x7ffU, 0U }; ! long_double_t ip_ld_nan = { 0xffffffffU, 0xffffffffU, 0x7fffU, 0U }; ! ! int do_brackets = 1; ! int leading_zero = 1; ! char *p; ! ! ip_ld_cast_nan = *(long_double_t *)&ld_cast_nan; ! ! if (was_double) ! { ! d = (double)ld; ! ip_d = *(double_t *)&d; ! } ! ! if (do_upper) ! digs = HEX_UPPER_DIGITS; ! else ! digs = HEX_LOWER_DIGITS; ! ! strcpy(startp, do_upper ? "NAN" : "nan"); ! ! /* If the NaN is one of the following, don't expand the brackets: ! * ! * 1. a long-double NaN; ! * 2. a double NaN; ! * 3. a float NaN (NB: it's been cast to long double). ! */ ! if ( (ip.manh == ip_ld_nan.mantissah) ! && (ip.manl == ip_ld_nan.mantissal)) ! do_brackets = 0; ! ! /* TODO: I think we need to test for double NaN cast ! * to a long double too. Maybe one test when !was_double, ! * one test when was_double? */ ! if ( (ip_d.mantissah == ip_d_nan.mantissah) ! && (ip_d.mantissal == ip_d_nan.mantissal)) ! do_brackets = 0; ! ! if ( (ip.manh == ip_ld_cast_nan.mantissah) ! && (ip.manl == ip_ld_cast_nan.mantissal)) ! do_brackets = 0; ! ! if (do_brackets) ! { ! strcat(startp, "(0x"); ! ! p = startp + strlen(startp); ! leading_zero = hexify(was_double ? ip_d.mantissah : ip.manh, ! &p, leading_zero, digs); ! leading_zero = hexify(was_double ? ip_d.mantissal : ip.manl, ! &p, leading_zero, digs); ! ! /* If no digits have been written, just write 0. */ ! if (leading_zero) ! { ! *p = digs[0]; ! p++; ! } ! ! *p = '\0'; ! ! strcat(startp, ")"); ! } ! } ! ! static int ! isspeciall(long double ld, ! const int was_double /* was double converted to a long double? */, ! const int do_upper /* inf & nan should be upper-case? */, ! char *signp, char *startp, char *endp) { ! struct IEEExp ip = *(struct IEEExp *)&ld; ! /* TODO: Buffer overflows? */ /* Unnormals: the MSB of mantissa is non-zero, but the exponent is not zero either. */ ! if ((ip.manh & 0x80000000U) == 0 && ip.exp != 0) { ! char *bufp = startp; ! ! if (ip.sign) *bufp++ = '-'; strcpy(bufp, UNNORMAL_REP); ! return strlen(bufp) + ip.sign; } ! ! if (ip.exp != 0x7fffU) return(0); ! ! if (ip.sign) ! *signp = '-'; ! ! if (!(ip.manh & 0x7fffffffU) && !ip.manl) ! strcpy(startp, do_upper ? "INF" : "inf"); else ! addnan(ld, ip, was_double, do_upper, startp, endp); ! ! return(strlen(startp)); }