From 4bd22eb7308143df7734a7b504f4fd0169a0e6da Mon Sep 17 00:00:00 2001 From: Marcus Comstedt <marcus@mc.pp.se> Date: Mon, 25 May 1998 22:47:47 +0200 Subject: [PATCH] Added %F format to sscanf. Rev: src/opcodes.c:1.27 --- src/opcodes.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 1 deletion(-) diff --git a/src/opcodes.c b/src/opcodes.c index 57a9a19455..fbc4da4850 100644 --- a/src/opcodes.c +++ b/src/opcodes.c @@ -22,7 +22,7 @@ #include "builtin_functions.h" #include "module_support.h" -RCSID("$Id: opcodes.c,v 1.26 1998/05/25 16:41:23 grubba Exp $"); +RCSID("$Id: opcodes.c,v 1.27 1998/05/25 20:47:47 marcus Exp $"); void index_no_free(struct svalue *to,struct svalue *what,struct svalue *ind) { @@ -424,6 +424,97 @@ static int read_set(unsigned char *match,int cnt,char *set,int match_len) } + +/* Parse binary IEEE strings on a machine which uses a different kind + of floating point internally */ + +#ifndef FLOAT_IS_IEEE_BIG +#ifndef FLOAT_IS_IEEE_LITTLE +#define NEED_CUSTOM_IEEE +#endif +#endif +#ifndef NEED_CUSTOM_IEEE +#ifndef DOUBLE_IS_IEEE_BIG +#ifndef DOUBLE_IS_IEEE_LITTLE +#define NEED_CUSTOM_IEEE +#endif +#endif +#endif + +#ifdef NEED_CUSTOM_IEEE + +#if HAVE_LDEXP +#define LDEXP ldexp +#else +extern double LDEXP(double x, int exp); /* defined in encode.c */ +#endif + +INLINE static float low_parse_IEEE_float(char *b, int sz) +{ + unsigned INT32 f, extra_f; + int s, e; + unsigned char x[4]; + double r; + + x[0] = EXTRACT_UCHAR(b); + x[1] = EXTRACT_UCHAR(b+1); + x[2] = EXTRACT_UCHAR(b+2); + x[3] = EXTRACT_UCHAR(b+3); + s = ((x[0]&0x80)? 1 : 0); + + if(sz==4) { + e = (((int)(x[0]&0x7f))<<1)|((x[1]&0x80)>>7); + f = (((unsigned INT32)(x[1]&0x7f))<<16)|(((unsigned INT32)x[2])<<8)|x[3]; + extra_f = 0; + if(e==255) + e = 9999; + else if(e>0) { + f |= 0x00800000; + e -= 127+23; + } else + e -= 126+23; + } else { + e = (((int)(x[0]&0x7f))<<4)|((x[1]&0xf0)>>4); + f = (((unsigned INT32)(x[1]&0x0f))<<16)|(((unsigned INT32)x[2])<<8)|x[3]; + extra_f = (((unsigned INT32)EXTRACT_UCHAR(b+4))<<24)| + (((unsigned INT32)EXTRACT_UCHAR(b+5))<<16)| + (((unsigned INT32)EXTRACT_UCHAR(b+6))<<8)| + ((unsigned INT32)EXTRACT_UCHAR(b+7)); + if(e==2047) + e = 9999; + else if(e>0) { + f |= 0x00100000; + e -= 1023+20; + } else + e -= 1022+20; + } + if(e>=9999) + if(f||extra_f) { + /* NAN */ + + /* Hmm... No idea how to generate NaN in a portable way. */ + /* Let's turn it into a 0 for now... */ + return (float)0.0; + } else { + /* +/- Infinity */ +#ifdef HUGE_VAL + return (float)(s? -HUGE_VAL:HUGE_VAL); +#else + /* This number is infinite enough... :) */ + e = 1024; + f = 1; + extra_f = 0; +#endif + } + + r = (double)f; + if(extra_f) + r += ((double)extra_f)/4294967296.0; + return (float)(s? -LDEXP(r, e):LDEXP(r, e)); +} + +#endif + static INT32 really_low_sscanf(char *input, long input_len, char *match, @@ -707,6 +798,84 @@ static INT32 really_low_sscanf(char *input, break; } + case 'F': + if(field_length == -1) field_length = 4; + if(field_length != 4 && field_length != 8) + error("Invalid IEEE width %d in sscanf format string.\n", + field_length); + if(eye+field_length > input_len) + { + chars_matched[0]=eye; + return matches; + } + sval.type=T_FLOAT; +#ifdef __CHECKER__ + sval.subtype=0; +#endif + switch(field_length) { + case 4: +#ifdef FLOAT_IS_IEEE_BIG + { + float f; + ((char *)&f)[0] = *(input+eye); + ((char *)&f)[1] = *(input+eye+1); + ((char *)&f)[2] = *(input+eye+2); + ((char *)&f)[3] = *(input+eye+3); + sval.u.float_number = f; + } +#else +#ifdef FLOAT_IS_IEEE_LITTLE + { + float f; + ((char *)&f)[3] = *(input+eye); + ((char *)&f)[2] = *(input+eye+1); + ((char *)&f)[1] = *(input+eye+2); + ((char *)&f)[0] = *(input+eye+3); + sval.u.float_number = f; + } +#else + sval.u.float_number = low_parse_IEEE_float(input+eye, 4); +#endif +#endif + eye += 4; + break; + case 8: +#ifdef DOUBLE_IS_IEEE_BIG + { + double d; + ((char *)&d)[0] = *(input+eye); + ((char *)&d)[1] = *(input+eye+1); + ((char *)&d)[2] = *(input+eye+2); + ((char *)&d)[3] = *(input+eye+3); + ((char *)&d)[4] = *(input+eye+4); + ((char *)&d)[5] = *(input+eye+5); + ((char *)&d)[6] = *(input+eye+6); + ((char *)&d)[7] = *(input+eye+7); + sval.u.float_number = (float)d; + } +#else +#ifdef DOUBLE_IS_IEEE_LITTLE + { + double d; + ((char *)&d)[7] = *(input+eye); + ((char *)&d)[6] = *(input+eye+1); + ((char *)&d)[5] = *(input+eye+2); + ((char *)&d)[4] = *(input+eye+3); + ((char *)&d)[3] = *(input+eye+4); + ((char *)&d)[2] = *(input+eye+5); + ((char *)&d)[1] = *(input+eye+6); + ((char *)&d)[0] = *(input+eye+7); + sval.u.float_number = (float)d; + } +#else + sval.u.float_number = low_parse_IEEE_float(input+eye, 8); +#endif +#endif + eye += 8; + break; + } + break; + case 's': if(field_length != -1) { -- GitLab