diff --git a/interpreters/bas/value.c b/interpreters/bas/value.c index 6d0d54053..dafa93abe 100644 --- a/interpreters/bas/value.c +++ b/interpreters/bas/value.c @@ -1,4 +1,7 @@ -/* #includes */ /*{{{C}}}*//*{{{*/ +/**************************************************************************** + * Included Files + ****************************************************************************/ + #undef _POSIX_SOURCE #define _POSIX_SOURCE 1 #undef _POSIX_C_SOURCE @@ -10,22 +13,27 @@ #include #include #include + #ifdef HAVE_GETTEXT -#include -#define _(String) gettext(String) +# include +# define _(String) gettext(String) #else -#define _(String) String +# define _(String) String #endif + #include #include + /* Buggy on some systems */ + #if 0 -#ifdef HAVE_TGMATH_H -#include -#endif +# ifdef HAVE_TGMATH_H +# include +# endif #else extern long int lrint(double x); #endif + #include #include #include @@ -35,32 +43,27 @@ extern long int lrint(double x); #include "value.h" #ifdef USE_DMALLOC -#include "dmalloc.h" +# include "dmalloc.h" #endif -/*}}}*/ -/* variables */ /*{{{*/ -static const char *typestr[]= +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char *typestr[] = { - (const char*)0, - (const char*)0, + (const char *)0, + (const char *)0, "integer", - (const char*)0, + (const char *)0, "real", "string", "void" }; /* for xgettext */ -#if 0 -_("integer") -_("real") -_("string") -_("void") -#endif -/*}}}*/ -const enum ValueType Value_commonType[V_VOID+1][V_VOID+1]= +const enum ValueType Value_commonType[V_VOID + 1][V_VOID + 1] = { { 0, 0, 0, 0, 0, 0, 0 }, { 0, V_ERROR, V_ERROR, V_ERROR, V_ERROR, V_ERROR, V_ERROR }, @@ -78,1394 +81,1649 @@ long int lrint(double d) } #endif -static void format_double(struct String *buf, double value, int width, int precision, int exponent) /*{{{*/ +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void format_double(struct String *buf, double value, int width, + int precision, int exponent) { if (exponent) - { - size_t len; - char *e; - int en; + { + size_t len; + char *e; + int en; - len=buf->length; - String_appendPrintf(buf,"%.*E",width-1-(precision>=0),value); - if (buf->character[len+1]=='.') String_delete(buf,len+1,1); - if (precision>=0) String_insertChar(buf,len+width-precision-1,'.'); - for (e=buf->character+buf->length-1; e>=buf->character && *e!='E'; --e); - ++e; - en=strtol(e,(char**)0,10); - en=en+2-(width-precision); - len=e-buf->character; - String_delete(buf,len,buf->length-len); - String_appendPrintf(buf,"%+0*d",exponent-1,en); - } - else if (precision>0) String_appendPrintf(buf,"%.*f",precision,value); - else if (precision==0) String_appendPrintf(buf,"%.f.",value); - else if (width) String_appendPrintf(buf,"%.f",value); + len = buf->length; + String_appendPrintf(buf, "%.*E", width - 1 - (precision >= 0), value); + if (buf->character[len + 1] == '.') + String_delete(buf, len + 1, 1); + + if (precision >= 0) + String_insertChar(buf, len + width - precision - 1, '.'); + + for (e = buf->character + buf->length - 1; + e >= buf->character && *e != 'E'; --e); + + ++e; + en = strtol(e, (char **)0, 10); + en = en + 2 - (width - precision); + len = e - buf->character; + String_delete(buf, len, buf->length - len); + String_appendPrintf(buf, "%+0*d", exponent - 1, en); + } + else if (precision > 0) + String_appendPrintf(buf, "%.*f", precision, value); + else if (precision == 0) + String_appendPrintf(buf, "%.f.", value); + else if (width) + String_appendPrintf(buf, "%.f", value); else - { - double x=value; - - if (x<0.0001 || x>=10000000.0) /* print scientific notation */ { - String_appendPrintf(buf,"%.7g",value); - } - else /* print decimal numbers or integers, if possible */ - { - int o,n,p=6; + double x = value; - while (x>=10.0 && p>0) { x/=10.0; --p; } - o=buf->length; - String_appendPrintf(buf,"%.*f",p,value); - n=buf->length; - if (memchr(buf->character+o,'.',n-o)) - { - while (buf->character[buf->length-1]=='0') --buf->length; - if (buf->character[buf->length-1]=='.') --buf->length; - } - } - } -} -/*}}}*/ + if (x < 0.0001 || x >= 10000000.0) /* print scientific notation */ + { + String_appendPrintf(buf, "%.7g", value); + } + else /* print decimal numbers or integers, if * + * possible */ + { + int o, n, p = 6; -double Value_trunc(double d) /*{{{*/ -{ - return (d<0.0?ceil(d):floor(d)); + while (x >= 10.0 && p > 0) + { + x /= 10.0; + --p; + } + o = buf->length; + String_appendPrintf(buf, "%.*f", p, value); + n = buf->length; + if (memchr(buf->character + o, '.', n - o)) + { + while (buf->character[buf->length - 1] == '0') + --buf->length; + if (buf->character[buf->length - 1] == '.') + --buf->length; + } + } + } } -/*}}}*/ -double Value_round(double d) /*{{{*/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +double Value_trunc(double d) { - return (d<0.0?ceil(d-0.5):floor(d+0.5)); + return (d < 0.0 ? ceil(d) : floor(d)); } -/*}}}*/ -long int Value_toi(double d, int *overflow) /*{{{*/ + +double Value_round(double d) { - d=Value_round(d); - *overflow=(dLONG_MAX); + return (d < 0.0 ? ceil(d - 0.5) : floor(d + 0.5)); +} + +long int Value_toi(double d, int *overflow) +{ + d = Value_round(d); + *overflow = (d < LONG_MIN || d > LONG_MAX); return lrint(d); } -/*}}}*/ -long int Value_vali(const char *s, char **end, int *overflow) /*{{{*/ + +long int Value_vali(const char *s, char **end, int *overflow) { long int n; - errno=0; - if (*s=='&' && tolower(*(s+1))=='h') n=strtoul(s+2,end,16); - else if (*s=='&' && tolower(*(s+1))=='o') n=strtoul(s+2,end,8); - else n=strtol(s,end,10); - *overflow=(errno==ERANGE); + errno = 0; + if (*s == '&' && tolower(*(s + 1)) == 'h') + n = strtoul(s + 2, end, 16); + else if (*s == '&' && tolower(*(s + 1)) == 'o') + n = strtoul(s + 2, end, 8); + else + n = strtol(s, end, 10); + + *overflow = (errno == ERANGE); return n; } -/*}}}*/ -double Value_vald(const char *s, char **end, int *overflow) /*{{{*/ + +double Value_vald(const char *s, char **end, int *overflow) { double d; - errno=0; - d=strtod(s,end); - *overflow=(errno==ERANGE); + errno = 0; + d = strtod(s, end); + *overflow = (errno == ERANGE); return d; } -/*}}}*/ -struct Value *Value_new_NIL(struct Value *this) /*{{{*/ +struct Value *Value_new_NIL(struct Value *this) { - assert(this!=(struct Value*)0); - this->type=V_NIL; + assert(this != (struct Value *)0); + this->type = V_NIL; return this; } -/*}}}*/ -struct Value *Value_new_ERROR(struct Value *this, int code, const char *error, ...) /*{{{*/ + +struct Value *Value_new_ERROR(struct Value *this, int code, const char *error, + ...) { va_list ap; char buf[128]; - assert(this!=(struct Value*)0); - va_start(ap,error); - vsprintf(buf,error,ap); + assert(this != (struct Value *)0); + va_start(ap, error); + vsprintf(buf, error, ap); va_end(ap); - this->type=V_ERROR; - this->u.error.code=code; - this->u.error.msg=strcpy(malloc(strlen(buf)+1),buf); + this->type = V_ERROR; + this->u.error.code = code; + this->u.error.msg = strcpy(malloc(strlen(buf) + 1), buf); return this; } -/*}}}*/ -struct Value *Value_new_INTEGER(struct Value *this, int n) /*{{{*/ + +struct Value *Value_new_INTEGER(struct Value *this, int n) { - assert(this!=(struct Value*)0); - this->type=V_INTEGER; - this->u.integer=n; + assert(this != (struct Value *)0); + this->type = V_INTEGER; + this->u.integer = n; return this; } -/*}}}*/ -struct Value *Value_new_REAL(struct Value *this, double n) /*{{{*/ + +struct Value *Value_new_REAL(struct Value *this, double n) { - assert(this!=(struct Value*)0); - this->type=V_REAL; - this->u.real=n; + assert(this != (struct Value *)0); + this->type = V_REAL; + this->u.real = n; return this; } -/*}}}*/ -struct Value *Value_new_STRING(struct Value *this) /*{{{*/ + +struct Value *Value_new_STRING(struct Value *this) { - assert(this!=(struct Value*)0); - this->type=V_STRING; + assert(this != (struct Value *)0); + this->type = V_STRING; String_new(&this->u.string); return this; } -/*}}}*/ -struct Value *Value_new_VOID(struct Value *this) /*{{{*/ + +struct Value *Value_new_VOID(struct Value *this) { - assert(this!=(struct Value*)0); - this->type=V_VOID; + assert(this != (struct Value *)0); + this->type = V_VOID; return this; } -/*}}}*/ -struct Value *Value_new_null(struct Value *this, enum ValueType type) /*{{{*/ + +struct Value *Value_new_null(struct Value *this, enum ValueType type) { - assert(this!=(struct Value*)0); + assert(this != (struct Value *)0); switch (type) - { + { case V_INTEGER: - { - this->type=V_INTEGER; - this->u.integer=0; - break; - } + { + this->type = V_INTEGER; + this->u.integer = 0; + break; + } case V_REAL: - { - this->type=V_REAL; - this->u.real=0.0; - break; - } + { + this->type = V_REAL; + this->u.real = 0.0; + break; + } case V_STRING: - { - this->type=V_STRING; - String_new(&this->u.string); - break; - } + { + this->type = V_STRING; + String_new(&this->u.string); + break; + } case V_VOID: - { - this->type=V_VOID; - break; + { + this->type = V_VOID; + break; + } + default: + assert(0); } - default: assert(0); - } + return this; } -/*}}}*/ -int Value_isNull(const struct Value *this) /*{{{*/ + +int Value_isNull(const struct Value *this) { switch (this->type) - { - case V_INTEGER: return (this->u.integer==0); - case V_REAL: return (this->u.real==0.0); - case V_STRING: return (this->u.string.length==0); - default: assert(0); - } + { + case V_INTEGER: + return (this->u.integer == 0); + case V_REAL: + return (this->u.real == 0.0); + case V_STRING: + return (this->u.string.length == 0); + default: + assert(0); + } + return -1; } -/*}}}*/ -void Value_destroy(struct Value *this) /*{{{*/ + +void Value_destroy(struct Value *this) { - assert(this!=(struct Value*)0); + assert(this != (struct Value *)0); switch (this->type) - { - case V_ERROR: free(this->u.error.msg); break; - case V_INTEGER: break; - case V_NIL: break; - case V_REAL: break; - case V_STRING: String_destroy(&this->u.string); break; - case V_VOID: break; - default: assert(0); - } - this->type=0; -} -/*}}}*/ -struct Value *Value_clone(struct Value *this, const struct Value *original) /*{{{*/ -{ - assert(this!=(struct Value*)0); - assert(original!=(struct Value*)0); - switch (original->type) - { + { case V_ERROR: - { - strcpy(this->u.error.msg=malloc(strlen(original->u.error.msg)+1),original->u.error.msg); - this->u.error.code=original->u.error.code; + free(this->u.error.msg); break; + case V_INTEGER: + break; + case V_NIL: + break; + case V_REAL: + break; + case V_STRING: + String_destroy(&this->u.string); + break; + case V_VOID: + break; + default: + assert(0); } - case V_INTEGER: this->u.integer=original->u.integer; break; - case V_NIL: break; - case V_REAL: this->u.real=original->u.real; break; - case V_STRING: String_clone(&this->u.string,&original->u.string); break; - default: assert(0); - } - this->type=original->type; + + this->type = 0; +} + +struct Value *Value_clone(struct Value *this, const struct Value *original) +{ + assert(this != (struct Value *)0); + assert(original != (struct Value *)0); + switch (original->type) + { + case V_ERROR: + { + strcpy(this->u.error.msg = + malloc(strlen(original->u.error.msg) + 1), + original->u.error.msg); + this->u.error.code = original->u.error.code; + break; + } + case V_INTEGER: + this->u.integer = original->u.integer; + break; + case V_NIL: + break; + case V_REAL: + this->u.real = original->u.real; + break; + case V_STRING: + String_clone(&this->u.string, &original->u.string); + break; + default: + assert(0); + } + + this->type = original->type; return this; } -/*}}}*/ -struct Value *Value_uplus(struct Value *this, int calc) /*{{{*/ + +struct Value *Value_uplus(struct Value *this, int calc) { switch (this->type) - { + { case V_INTEGER: case V_REAL: - { - break; - } + { + break; + } case V_STRING: - { - Value_destroy(this); - Value_new_ERROR(this,INVALIDUOPERAND); - break; + { + Value_destroy(this); + Value_new_ERROR(this, INVALIDUOPERAND); + break; + } + default: + assert(0); } - default: assert(0); - } + return this; } -/*}}}*/ -struct Value *Value_uneg(struct Value *this, int calc) /*{{{*/ + +struct Value *Value_uneg(struct Value *this, int calc) { switch (this->type) - { + { case V_INTEGER: - { - if (calc) this->u.integer=-this->u.integer; - break; - } + { + if (calc) + this->u.integer = -this->u.integer; + break; + } case V_REAL: - { - if (calc) this->u.real=-this->u.real; - break; - } + { + if (calc) + this->u.real = -this->u.real; + break; + } case V_STRING: - { - Value_destroy(this); - Value_new_ERROR(this,INVALIDUOPERAND); - break; + { + Value_destroy(this); + Value_new_ERROR(this, INVALIDUOPERAND); + break; + } + default: + assert(0); } - default: assert(0); - } + return this; } -/*}}}*/ -struct Value *Value_unot(struct Value *this, int calc) /*{{{*/ + +struct Value *Value_unot(struct Value *this, int calc) { switch (this->type) - { + { case V_INTEGER: - { - if (calc) this->u.integer=~this->u.integer; - break; - } - case V_REAL: - { - Value_retype(this,V_INTEGER); - if (calc) this->u.integer=~this->u.integer; - break; - } - case V_STRING: - { - Value_destroy(this); - Value_new_ERROR(this,INVALIDUOPERAND); - break; - } - default: assert(0); - } - return this; -} -/*}}}*/ -struct Value *Value_add(struct Value *this, struct Value *x, int calc) /*{{{*/ -{ - switch (Value_commonType[this->type][x->type]) - { - case V_INTEGER: - { - VALUE_RETYPE(this,V_INTEGER); - VALUE_RETYPE(x,V_INTEGER); - if (calc) this->u.integer+=x->u.integer; - break; - } - case V_REAL: - { - VALUE_RETYPE(this,V_REAL); - VALUE_RETYPE(x,V_REAL); - if (calc) this->u.real+=x->u.real; - break; - } - case V_STRING: - { - if (calc) String_appendString(&this->u.string,&x->u.string); - break; - } - default: assert(0); - } - return this; -} -/*}}}*/ -struct Value *Value_sub(struct Value *this, struct Value *x, int calc) /*{{{*/ -{ - switch (Value_commonType[this->type][x->type]) - { - case V_INTEGER: - { - VALUE_RETYPE(this,V_INTEGER); - VALUE_RETYPE(x,V_INTEGER); - if (calc) this->u.integer-=x->u.integer; - break; - } - case V_REAL: - { - VALUE_RETYPE(this,V_REAL); - VALUE_RETYPE(x,V_REAL); - if (calc) this->u.real-=x->u.real; - break; - } - case V_STRING: - { - Value_destroy(this); - Value_new_ERROR(this,INVALIDOPERAND); - break; - } - default: assert(0); - } - return this; -} -/*}}}*/ -struct Value *Value_mult(struct Value *this, struct Value *x, int calc) /*{{{*/ -{ - switch (Value_commonType[this->type][x->type]) - { - case V_INTEGER: - { - VALUE_RETYPE(this,V_INTEGER); - VALUE_RETYPE(x,V_INTEGER); - if (calc) this->u.integer*=x->u.integer; - break; - } - case V_REAL: - { - VALUE_RETYPE(this,V_REAL); - VALUE_RETYPE(x,V_REAL); - if (calc) this->u.real*=x->u.real; - break; - } - case V_STRING: - { - Value_destroy(this); - Value_new_ERROR(this,INVALIDOPERAND); - break; - } - default: assert(0); - } - return this; -} -/*}}}*/ -struct Value *Value_div(struct Value *this, struct Value *x, int calc) /*{{{*/ -{ - switch (Value_commonType[this->type][x->type]) - { - case V_INTEGER: - { - VALUE_RETYPE(this,V_REAL); - VALUE_RETYPE(x,V_REAL); - if (calc) { - if (x->u.real==0) - { - Value_destroy(this); - Value_new_ERROR(this,UNDEFINED,"Division by zero"); - } - else this->u.real/=x->u.real; + if (calc) + this->u.integer = ~this->u.integer; + break; } - break; - } case V_REAL: - { - VALUE_RETYPE(this,V_REAL); - VALUE_RETYPE(x,V_REAL); - if (calc) { - if (x->u.real==0.0) - { - Value_destroy(this); - Value_new_ERROR(this,UNDEFINED,"Division by zero"); - } - else this->u.real/=x->u.real; + Value_retype(this, V_INTEGER); + if (calc) + this->u.integer = ~this->u.integer; + break; } - break; - } case V_STRING: - { - Value_destroy(this); - Value_new_ERROR(this,INVALIDOPERAND); - break; + { + Value_destroy(this); + Value_new_ERROR(this, INVALIDUOPERAND); + break; + } + default: + assert(0); } - default: assert(0); - } + return this; } -/*}}}*/ -struct Value *Value_idiv(struct Value *this, struct Value *x, int calc) /*{{{*/ + +struct Value *Value_add(struct Value *this, struct Value *x, int calc) { switch (Value_commonType[this->type][x->type]) - { + { case V_INTEGER: - { - VALUE_RETYPE(this,V_INTEGER); - VALUE_RETYPE(x,V_INTEGER); - if (calc) { - if (x->u.integer==0) - { - Value_destroy(this); - Value_new_ERROR(this,UNDEFINED,"Division by zero"); - } - else this->u.integer/=x->u.integer; + VALUE_RETYPE(this, V_INTEGER); + VALUE_RETYPE(x, V_INTEGER); + if (calc) + this->u.integer += x->u.integer; + break; } - break; - } case V_REAL: - { - VALUE_RETYPE(this,V_REAL); - VALUE_RETYPE(x,V_REAL); - if (calc) { - if (x->u.real==0.0) - { - Value_destroy(this); - Value_new_ERROR(this,UNDEFINED,"Division by zero"); - } - else this->u.real=Value_trunc(this->u.real/x->u.real); + VALUE_RETYPE(this, V_REAL); + VALUE_RETYPE(x, V_REAL); + if (calc) + this->u.real += x->u.real; + break; } - break; - } case V_STRING: - { - Value_destroy(this); - Value_new_ERROR(this,INVALIDOPERAND); - break; + { + if (calc) + String_appendString(&this->u.string, &x->u.string); + break; + } + default: + assert(0); } - default: assert(0); - } + return this; } -/*}}}*/ -struct Value *Value_mod(struct Value *this, struct Value *x, int calc) /*{{{*/ + +struct Value *Value_sub(struct Value *this, struct Value *x, int calc) { switch (Value_commonType[this->type][x->type]) - { + { case V_INTEGER: - { - VALUE_RETYPE(this,V_INTEGER); - VALUE_RETYPE(x,V_INTEGER); - if (calc) { - if (x->u.integer==0) - { - Value_destroy(this); - Value_new_ERROR(this,UNDEFINED,"Modulo by zero"); - } - else this->u.integer%=x->u.integer; + VALUE_RETYPE(this, V_INTEGER); + VALUE_RETYPE(x, V_INTEGER); + if (calc) + this->u.integer -= x->u.integer; + break; } - break; - } case V_REAL: - { - VALUE_RETYPE(this,V_REAL); - VALUE_RETYPE(x,V_REAL); - if (calc) { - if (x->u.real==0.0) - { - Value_destroy(this); - Value_new_ERROR(this,UNDEFINED,"Modulo by zero"); - } - else this->u.real=fmod(this->u.real,x->u.real); + VALUE_RETYPE(this, V_REAL); + VALUE_RETYPE(x, V_REAL); + if (calc) + this->u.real -= x->u.real; + break; } - break; - } case V_STRING: - { - Value_destroy(this); - Value_new_ERROR(this,INVALIDOPERAND); - break; + { + Value_destroy(this); + Value_new_ERROR(this, INVALIDOPERAND); + break; + } + default: + assert(0); } - default: assert(0); - } + return this; } -/*}}}*/ -struct Value *Value_pow(struct Value *this, struct Value *x, int calc) /*{{{*/ + +struct Value *Value_mult(struct Value *this, struct Value *x, int calc) { switch (Value_commonType[this->type][x->type]) - { - case V_INTEGER: { - VALUE_RETYPE(this,V_INTEGER); - VALUE_RETYPE(x,V_INTEGER); - if (calc) + case V_INTEGER: { - if (this->u.integer==0 && x->u.integer==0) - { - Value_destroy(this); - Value_new_ERROR(this,UNDEFINED,"0^0"); - } - else if (x->u.integer>0) this->u.integer=pow(this->u.integer,x->u.integer); + VALUE_RETYPE(this, V_INTEGER); + VALUE_RETYPE(x, V_INTEGER); + if (calc) + this->u.integer *= x->u.integer; + break; + } + case V_REAL: + { + VALUE_RETYPE(this, V_REAL); + VALUE_RETYPE(x, V_REAL); + if (calc) + this->u.real *= x->u.real; + break; + } + case V_STRING: + { + Value_destroy(this); + Value_new_ERROR(this, INVALIDOPERAND); + break; + } + default: + assert(0); + } + + return this; +} + +struct Value *Value_div(struct Value *this, struct Value *x, int calc) +{ + switch (Value_commonType[this->type][x->type]) + { + case V_INTEGER: + { + VALUE_RETYPE(this, V_REAL); + VALUE_RETYPE(x, V_REAL); + if (calc) + { + if (x->u.real == 0) + { + Value_destroy(this); + Value_new_ERROR(this, UNDEFINED, "Division by zero"); + } + else + this->u.real /= x->u.real; + } + break; + } + case V_REAL: + { + VALUE_RETYPE(this, V_REAL); + VALUE_RETYPE(x, V_REAL); + if (calc) + { + if (x->u.real == 0.0) + { + Value_destroy(this); + Value_new_ERROR(this, UNDEFINED, "Division by zero"); + } + else + this->u.real /= x->u.real; + } + break; + } + case V_STRING: + { + Value_destroy(this); + Value_new_ERROR(this, INVALIDOPERAND); + break; + } + default: + assert(0); + } + return this; +} + +struct Value *Value_idiv(struct Value *this, struct Value *x, int calc) +{ + switch (Value_commonType[this->type][x->type]) + { + case V_INTEGER: + { + VALUE_RETYPE(this, V_INTEGER); + VALUE_RETYPE(x, V_INTEGER); + if (calc) + { + if (x->u.integer == 0) + { + Value_destroy(this); + Value_new_ERROR(this, UNDEFINED, "Division by zero"); + } + else + this->u.integer /= x->u.integer; + } + break; + } + case V_REAL: + { + VALUE_RETYPE(this, V_REAL); + VALUE_RETYPE(x, V_REAL); + if (calc) + { + if (x->u.real == 0.0) + { + Value_destroy(this); + Value_new_ERROR(this, UNDEFINED, "Division by zero"); + } + else + this->u.real = Value_trunc(this->u.real / x->u.real); + } + break; + } + case V_STRING: + { + Value_destroy(this); + Value_new_ERROR(this, INVALIDOPERAND); + break; + } + default: + assert(0); + } + + return this; +} + +struct Value *Value_mod(struct Value *this, struct Value *x, int calc) +{ + switch (Value_commonType[this->type][x->type]) + { + case V_INTEGER: + { + VALUE_RETYPE(this, V_INTEGER); + VALUE_RETYPE(x, V_INTEGER); + if (calc) + { + if (x->u.integer == 0) + { + Value_destroy(this); + Value_new_ERROR(this, UNDEFINED, "Modulo by zero"); + } + else + this->u.integer %= x->u.integer; + } + break; + } + case V_REAL: + { + VALUE_RETYPE(this, V_REAL); + VALUE_RETYPE(x, V_REAL); + if (calc) + { + if (x->u.real == 0.0) + { + Value_destroy(this); + Value_new_ERROR(this, UNDEFINED, "Modulo by zero"); + } + else + this->u.real = fmod(this->u.real, x->u.real); + } + break; + } + case V_STRING: + { + Value_destroy(this); + Value_new_ERROR(this, INVALIDOPERAND); + break; + } + default: + assert(0); + } + + return this; +} + +struct Value *Value_pow(struct Value *this, struct Value *x, int calc) +{ + switch (Value_commonType[this->type][x->type]) + { + case V_INTEGER: + { + VALUE_RETYPE(this, V_INTEGER); + VALUE_RETYPE(x, V_INTEGER); + if (calc) + { + if (this->u.integer == 0 && x->u.integer == 0) + { + Value_destroy(this); + Value_new_ERROR(this, UNDEFINED, "0^0"); + } + else if (x->u.integer > 0) + this->u.integer = pow(this->u.integer, x->u.integer); + else + { + long int thisi = this->u.integer; + Value_destroy(this); + Value_new_REAL(this, pow(thisi, x->u.integer)); + } + } + break; + } + case V_REAL: + { + VALUE_RETYPE(this, V_REAL); + VALUE_RETYPE(x, V_REAL); + if (calc) + { + if (this->u.real == 0.0 && x->u.real == 0.0) + { + Value_destroy(this); + Value_new_ERROR(this, UNDEFINED, "0^0"); + } + else + this->u.real = pow(this->u.real, x->u.real); + } + break; + } + case V_STRING: + { + Value_destroy(this); + Value_new_ERROR(this, INVALIDOPERAND); + break; + } + default: + assert(0); + } + + return this; +} + +struct Value *Value_and(struct Value *this, struct Value *x, int calc) +{ + switch (Value_commonType[this->type][x->type]) + { + case V_INTEGER: + case V_REAL: + { + VALUE_RETYPE(this, V_INTEGER); + VALUE_RETYPE(x, V_INTEGER); + if (calc) + this->u.integer &= x->u.integer; + break; + } + case V_STRING: + { + Value_destroy(this); + Value_new_ERROR(this, INVALIDOPERAND); + break; + } + default: + assert(0); + } + + return this; +} + +struct Value *Value_or(struct Value *this, struct Value *x, int calc) +{ + switch (Value_commonType[this->type][x->type]) + { + case V_INTEGER: + case V_REAL: + { + VALUE_RETYPE(this, V_INTEGER); + VALUE_RETYPE(x, V_INTEGER); + if (calc) + this->u.integer |= x->u.integer; + break; + } + case V_STRING: + { + Value_destroy(this); + Value_new_ERROR(this, INVALIDOPERAND); + break; + } + default: + assert(0); + } + + return this; +} + +struct Value *Value_xor(struct Value *this, struct Value *x, int calc) +{ + switch (Value_commonType[this->type][x->type]) + { + case V_INTEGER: + case V_REAL: + { + VALUE_RETYPE(this, V_INTEGER); + VALUE_RETYPE(x, V_INTEGER); + if (calc) + this->u.integer ^= x->u.integer; + break; + } + case V_STRING: + { + Value_destroy(this); + Value_new_ERROR(this, INVALIDOPERAND); + break; + } + default: + assert(0); + } + + return this; +} + +struct Value *Value_eqv(struct Value *this, struct Value *x, int calc) +{ + switch (Value_commonType[this->type][x->type]) + { + case V_INTEGER: + case V_REAL: + { + VALUE_RETYPE(this, V_INTEGER); + VALUE_RETYPE(x, V_INTEGER); + if (calc) + this->u.integer = ~(this->u.integer ^ x->u.integer); + break; + } + case V_STRING: + { + Value_destroy(this); + Value_new_ERROR(this, INVALIDOPERAND); + break; + } + default: + assert(0); + } + + return this; +} + +struct Value *Value_imp(struct Value *this, struct Value *x, int calc) +{ + switch (Value_commonType[this->type][x->type]) + { + case V_INTEGER: + case V_REAL: + { + VALUE_RETYPE(this, V_INTEGER); + VALUE_RETYPE(x, V_INTEGER); + if (calc) + this->u.integer = (~this->u.integer) | x->u.integer; + break; + } + case V_STRING: + { + Value_destroy(this); + Value_new_ERROR(this, INVALIDOPERAND); + break; + } + default: + assert(0); + } + + return this; +} + +struct Value *Value_lt(struct Value *this, struct Value *x, int calc) +{ + switch (Value_commonType[this->type][x->type]) + { + case V_INTEGER: + { + VALUE_RETYPE(this, V_INTEGER); + VALUE_RETYPE(x, V_INTEGER); + if (calc) + this->u.integer = (this->u.integer < x->u.integer) ? -1 : 0; + break; + } + case V_REAL: + { + int v; + + VALUE_RETYPE(this, V_REAL); + VALUE_RETYPE(x, V_REAL); + if (calc) + v = (this->u.real < x->u.real) ? -1 : 0; else - { - long int thisi=this->u.integer; - Value_destroy(this); - Value_new_REAL(this,pow(thisi,x->u.integer)); - } + v = 0; + Value_destroy(this); + Value_new_INTEGER(this, v); + break; } - break; - } - case V_REAL: - { - VALUE_RETYPE(this,V_REAL); - VALUE_RETYPE(x,V_REAL); - if (calc) + case V_STRING: { - if (this->u.real==0.0 && x->u.real==0.0) - { - Value_destroy(this); - Value_new_ERROR(this,UNDEFINED,"0^0"); - } - else this->u.real=pow(this->u.real,x->u.real); + int v; + + if (calc) + v = (String_cmp(&this->u.string, &x->u.string) < 0) ? -1 : 0; + else + v = 0; + Value_destroy(this); + Value_new_INTEGER(this, v); + break; } - break; + default: + assert(0); } - case V_STRING: - { - Value_destroy(this); - Value_new_ERROR(this,INVALIDOPERAND); - break; - } - default: assert(0); - } + return this; } -/*}}}*/ -struct Value *Value_and(struct Value *this, struct Value *x, int calc) /*{{{*/ + +struct Value *Value_le(struct Value *this, struct Value *x, int calc) { switch (Value_commonType[this->type][x->type]) - { + { case V_INTEGER: + { + VALUE_RETYPE(this, V_INTEGER); + VALUE_RETYPE(x, V_INTEGER); + if (calc) + this->u.integer = (this->u.integer <= x->u.integer) ? -1 : 0; + break; + } case V_REAL: - { - VALUE_RETYPE(this,V_INTEGER); - VALUE_RETYPE(x,V_INTEGER); - if (calc) this->u.integer&=x->u.integer; - break; - } + { + int v; + + VALUE_RETYPE(this, V_REAL); + VALUE_RETYPE(x, V_REAL); + if (calc) + v = (this->u.real <= x->u.real) ? -1 : 0; + else + v = 0; + Value_destroy(this); + Value_new_INTEGER(this, v); + break; + } case V_STRING: - { - Value_destroy(this); - Value_new_ERROR(this,INVALIDOPERAND); - break; + { + int v; + + if (calc) + v = (String_cmp(&this->u.string, &x->u.string) <= 0) ? -1 : 0; + else + v = 0; + Value_destroy(this); + Value_new_INTEGER(this, v); + break; + } + default: + assert(0); } - default: assert(0); - } + return this; } -/*}}}*/ -struct Value *Value_or(struct Value *this, struct Value *x, int calc) /*{{{*/ + +struct Value *Value_eq(struct Value *this, struct Value *x, int calc) { switch (Value_commonType[this->type][x->type]) - { + { case V_INTEGER: + { + VALUE_RETYPE(this, V_INTEGER); + VALUE_RETYPE(x, V_INTEGER); + if (calc) + this->u.integer = (this->u.integer == x->u.integer) ? -1 : 0; + break; + } case V_REAL: - { - VALUE_RETYPE(this,V_INTEGER); - VALUE_RETYPE(x,V_INTEGER); - if (calc) this->u.integer|=x->u.integer; - break; - } + { + int v; + + VALUE_RETYPE(this, V_REAL); + VALUE_RETYPE(x, V_REAL); + if (calc) + v = (this->u.real == x->u.real) ? -1 : 0; + else + v = 0; + Value_destroy(this); + Value_new_INTEGER(this, v); + break; + } case V_STRING: - { - Value_destroy(this); - Value_new_ERROR(this,INVALIDOPERAND); - break; + { + int v; + + if (calc) + v = (String_cmp(&this->u.string, &x->u.string) == 0) ? -1 : 0; + else + v = 0; + Value_destroy(this); + Value_new_INTEGER(this, v); + break; + } + default: + assert(0); } - default: assert(0); - } + return this; } -/*}}}*/ -struct Value *Value_xor(struct Value *this, struct Value *x, int calc) /*{{{*/ + +struct Value *Value_ge(struct Value *this, struct Value *x, int calc) { switch (Value_commonType[this->type][x->type]) - { + { case V_INTEGER: + { + VALUE_RETYPE(this, V_INTEGER); + VALUE_RETYPE(x, V_INTEGER); + if (calc) + this->u.integer = (this->u.integer >= x->u.integer) ? -1 : 0; + break; + } case V_REAL: - { - VALUE_RETYPE(this,V_INTEGER); - VALUE_RETYPE(x,V_INTEGER); - if (calc) this->u.integer^=x->u.integer; - break; - } + { + int v; + + VALUE_RETYPE(this, V_REAL); + VALUE_RETYPE(x, V_REAL); + if (calc) + v = (this->u.real >= x->u.real) ? -1 : 0; + else + v = 0; + Value_destroy(this); + Value_new_INTEGER(this, v); + break; + } case V_STRING: - { - Value_destroy(this); - Value_new_ERROR(this,INVALIDOPERAND); - break; + { + int v; + + if (calc) + v = (String_cmp(&this->u.string, &x->u.string) >= 0) ? -1 : 0; + else + v = 0; + Value_destroy(this); + Value_new_INTEGER(this, v); + break; + } + default: + assert(0); } - default: assert(0); - } + return this; } -/*}}}*/ -struct Value *Value_eqv(struct Value *this, struct Value *x, int calc) /*{{{*/ + +struct Value *Value_gt(struct Value *this, struct Value *x, int calc) { switch (Value_commonType[this->type][x->type]) - { + { case V_INTEGER: + { + VALUE_RETYPE(this, V_INTEGER); + VALUE_RETYPE(x, V_INTEGER); + if (calc) + this->u.integer = (this->u.integer > x->u.integer) ? -1 : 0; + break; + } case V_REAL: - { - VALUE_RETYPE(this,V_INTEGER); - VALUE_RETYPE(x,V_INTEGER); - if (calc) this->u.integer=~(this->u.integer^x->u.integer); - break; - } + { + int v; + + VALUE_RETYPE(this, V_REAL); + VALUE_RETYPE(x, V_REAL); + if (calc) + v = (this->u.real > x->u.real) ? -1 : 0; + else + v = 0; + Value_destroy(this); + Value_new_INTEGER(this, v); + break; + } case V_STRING: - { - Value_destroy(this); - Value_new_ERROR(this,INVALIDOPERAND); - break; + { + int v; + + if (calc) + v = (String_cmp(&this->u.string, &x->u.string) > 0) ? -1 : 0; + else + v = 0; + Value_destroy(this); + Value_new_INTEGER(this, v); + break; + } + default: + assert(0); } - default: assert(0); - } + return this; } -/*}}}*/ -struct Value *Value_imp(struct Value *this, struct Value *x, int calc) /*{{{*/ + +struct Value *Value_ne(struct Value *this, struct Value *x, int calc) { switch (Value_commonType[this->type][x->type]) - { + { case V_INTEGER: + { + VALUE_RETYPE(this, V_INTEGER); + VALUE_RETYPE(x, V_INTEGER); + if (calc) + this->u.integer = (this->u.integer != x->u.integer) ? -1 : 0; + break; + } case V_REAL: - { - VALUE_RETYPE(this,V_INTEGER); - VALUE_RETYPE(x,V_INTEGER); - if (calc) this->u.integer=(~this->u.integer)|x->u.integer; - break; - } + { + int v; + + VALUE_RETYPE(this, V_REAL); + VALUE_RETYPE(x, V_REAL); + if (calc) + v = (this->u.real != x->u.real) ? -1 : 0; + else + v = 0; + Value_destroy(this); + Value_new_INTEGER(this, v); + break; + } case V_STRING: - { - Value_destroy(this); - Value_new_ERROR(this,INVALIDOPERAND); - break; + { + int v; + + if (calc) + v = String_cmp(&this->u.string, &x->u.string) ? -1 : 0; + else + v = 0; + Value_destroy(this); + Value_new_INTEGER(this, v); + break; + } + default: + assert(0); } - default: assert(0); - } + return this; } -/*}}}*/ -struct Value *Value_lt(struct Value *this, struct Value *x, int calc) /*{{{*/ -{ - switch (Value_commonType[this->type][x->type]) - { - case V_INTEGER: - { - VALUE_RETYPE(this,V_INTEGER); - VALUE_RETYPE(x,V_INTEGER); - if (calc) this->u.integer=(this->u.integeru.integer)?-1:0; - break; - } - case V_REAL: - { - int v; - VALUE_RETYPE(this,V_REAL); - VALUE_RETYPE(x,V_REAL); - if (calc) v=(this->u.realu.real)?-1:0; - else v=0; - Value_destroy(this); - Value_new_INTEGER(this,v); - break; - } - case V_STRING: - { - int v; - - if (calc) v=(String_cmp(&this->u.string,&x->u.string)<0)?-1:0; - else v=0; - Value_destroy(this); - Value_new_INTEGER(this,v); - break; - } - default: assert(0); - } - return this; -} -/*}}}*/ -struct Value *Value_le(struct Value *this, struct Value *x, int calc) /*{{{*/ -{ - switch (Value_commonType[this->type][x->type]) - { - case V_INTEGER: - { - VALUE_RETYPE(this,V_INTEGER); - VALUE_RETYPE(x,V_INTEGER); - if (calc) this->u.integer=(this->u.integer<=x->u.integer)?-1:0; - break; - } - case V_REAL: - { - int v; - - VALUE_RETYPE(this,V_REAL); - VALUE_RETYPE(x,V_REAL); - if (calc) v=(this->u.real<=x->u.real)?-1:0; - else v=0; - Value_destroy(this); - Value_new_INTEGER(this,v); - break; - } - case V_STRING: - { - int v; - - if (calc) v=(String_cmp(&this->u.string,&x->u.string)<=0)?-1:0; - else v=0; - Value_destroy(this); - Value_new_INTEGER(this,v); - break; - } - default: assert(0); - } - return this; -} -/*}}}*/ -struct Value *Value_eq(struct Value *this, struct Value *x, int calc) /*{{{*/ -{ - switch (Value_commonType[this->type][x->type]) - { - case V_INTEGER: - { - VALUE_RETYPE(this,V_INTEGER); - VALUE_RETYPE(x,V_INTEGER); - if (calc) this->u.integer=(this->u.integer==x->u.integer)?-1:0; - break; - } - case V_REAL: - { - int v; - - VALUE_RETYPE(this,V_REAL); - VALUE_RETYPE(x,V_REAL); - if (calc) v=(this->u.real==x->u.real)?-1:0; - else v=0; - Value_destroy(this); - Value_new_INTEGER(this,v); - break; - } - case V_STRING: - { - int v; - - if (calc) v=(String_cmp(&this->u.string,&x->u.string)==0)?-1:0; - else v=0; - Value_destroy(this); - Value_new_INTEGER(this,v); - break; - } - default: assert(0); - } - return this; -} -/*}}}*/ -struct Value *Value_ge(struct Value *this, struct Value *x, int calc) /*{{{*/ -{ - switch (Value_commonType[this->type][x->type]) - { - case V_INTEGER: - { - VALUE_RETYPE(this,V_INTEGER); - VALUE_RETYPE(x,V_INTEGER); - if (calc) this->u.integer=(this->u.integer>=x->u.integer)?-1:0; - break; - } - case V_REAL: - { - int v; - - VALUE_RETYPE(this,V_REAL); - VALUE_RETYPE(x,V_REAL); - if (calc) v=(this->u.real>=x->u.real)?-1:0; - else v=0; - Value_destroy(this); - Value_new_INTEGER(this,v); - break; - } - case V_STRING: - { - int v; - - if (calc) v=(String_cmp(&this->u.string,&x->u.string)>=0)?-1:0; - else v=0; - Value_destroy(this); - Value_new_INTEGER(this,v); - break; - } - default: assert(0); - } - return this; -} -/*}}}*/ -struct Value *Value_gt(struct Value *this, struct Value *x, int calc) /*{{{*/ -{ - switch (Value_commonType[this->type][x->type]) - { - case V_INTEGER: - { - VALUE_RETYPE(this,V_INTEGER); - VALUE_RETYPE(x,V_INTEGER); - if (calc) this->u.integer=(this->u.integer>x->u.integer)?-1:0; - break; - } - case V_REAL: - { - int v; - - VALUE_RETYPE(this,V_REAL); - VALUE_RETYPE(x,V_REAL); - if (calc) v=(this->u.real>x->u.real)?-1:0; - else v=0; - Value_destroy(this); - Value_new_INTEGER(this,v); - break; - } - case V_STRING: - { - int v; - - if (calc) v=(String_cmp(&this->u.string,&x->u.string)>0)?-1:0; - else v=0; - Value_destroy(this); - Value_new_INTEGER(this,v); - break; - } - default: assert(0); - } - return this; -} -/*}}}*/ -struct Value *Value_ne(struct Value *this, struct Value *x, int calc) /*{{{*/ -{ - switch (Value_commonType[this->type][x->type]) - { - case V_INTEGER: - { - VALUE_RETYPE(this,V_INTEGER); - VALUE_RETYPE(x,V_INTEGER); - if (calc) this->u.integer=(this->u.integer!=x->u.integer)?-1:0; - break; - } - case V_REAL: - { - int v; - - VALUE_RETYPE(this,V_REAL); - VALUE_RETYPE(x,V_REAL); - if (calc) v=(this->u.real!=x->u.real)?-1:0; - else v=0; - Value_destroy(this); - Value_new_INTEGER(this,v); - break; - } - case V_STRING: - { - int v; - - if (calc) v=String_cmp(&this->u.string,&x->u.string)?-1:0; - else v=0; - Value_destroy(this); - Value_new_INTEGER(this,v); - break; - } - default: assert(0); - } - return this; -} -/*}}}*/ -int Value_exitFor(struct Value *this, struct Value *limit, struct Value *step) /*{{{*/ +int Value_exitFor(struct Value *this, struct Value *limit, struct Value *step) { switch (this->type) - { - case V_INTEGER: return - ( - step->u.integer<0 - ? (this->u.integeru.integer) - : (this->u.integer>limit->u.integer) - ); - case V_REAL: return - ( - step->u.real<0.0 - ? (this->u.realu.real) - : (this->u.real>limit->u.real) - ); - case V_STRING: return (String_cmp(&this->u.string,&limit->u.string)>0); - default: assert(0); - } + { + case V_INTEGER: + return + (step->u.integer < 0 + ? (this->u.integer < limit->u.integer) + : (this->u.integer > limit->u.integer)); + case V_REAL: + return + (step->u.real < 0.0 + ? (this->u.real < limit->u.real) : (this->u.real > limit->u.real)); + case V_STRING: + return (String_cmp(&this->u.string, &limit->u.string) > 0); + default: + assert(0); + } return -1; } -/*}}}*/ -void Value_errorPrefix(struct Value *this, const char *prefix) /*{{{*/ -{ - size_t prefixlen,msglen; - assert(this->type==V_ERROR); - prefixlen=strlen(prefix); - msglen=strlen(this->u.error.msg); - this->u.error.msg=realloc(this->u.error.msg,prefixlen+msglen+1); - memmove(this->u.error.msg+prefixlen,this->u.error.msg,msglen); - memcpy(this->u.error.msg,prefix,prefixlen); -} -/*}}}*/ -void Value_errorSuffix(struct Value *this, const char *suffix) /*{{{*/ +void Value_errorPrefix(struct Value *this, const char *prefix) { - size_t suffixlen,msglen; + size_t prefixlen, msglen; - assert(this->type==V_ERROR); - suffixlen=strlen(suffix); - msglen=strlen(this->u.error.msg); - this->u.error.msg=realloc(this->u.error.msg,suffixlen+msglen+1); - memcpy(this->u.error.msg+msglen,suffix,suffixlen+1); + assert(this->type == V_ERROR); + prefixlen = strlen(prefix); + msglen = strlen(this->u.error.msg); + this->u.error.msg = realloc(this->u.error.msg, prefixlen + msglen + 1); + memmove(this->u.error.msg + prefixlen, this->u.error.msg, msglen); + memcpy(this->u.error.msg, prefix, prefixlen); } -/*}}}*/ -struct Value *Value_new_typeError(struct Value *this, enum ValueType t1, enum ValueType t2) /*{{{*/ + +void Value_errorSuffix(struct Value *this, const char *suffix) +{ + size_t suffixlen, msglen; + + assert(this->type == V_ERROR); + suffixlen = strlen(suffix); + msglen = strlen(this->u.error.msg); + this->u.error.msg = realloc(this->u.error.msg, suffixlen + msglen + 1); + memcpy(this->u.error.msg + msglen, suffix, suffixlen + 1); +} + +struct Value *Value_new_typeError(struct Value *this, enum ValueType t1, + enum ValueType t2) { assert(typestr[t1]); assert(typestr[t2]); - return Value_new_ERROR(this,TYPEMISMATCH1,_(typestr[t1]),_(typestr[t2])); + return Value_new_ERROR(this, TYPEMISMATCH1, _(typestr[t1]), _(typestr[t2])); } -/*}}}*/ -static void retypeError(struct Value *this, enum ValueType to) /*{{{*/ + +static void retypeError(struct Value *this, enum ValueType to) { - enum ValueType thisType=this->type; + enum ValueType thisType = this->type; assert(typestr[thisType]); assert(typestr[to]); Value_destroy(this); - Value_new_ERROR(this,TYPEMISMATCH1,_(typestr[thisType]),_(typestr[to])); + Value_new_ERROR(this, TYPEMISMATCH1, _(typestr[thisType]), _(typestr[to])); } -/*}}}*/ -struct Value *Value_retype(struct Value *this, enum ValueType type) /*{{{*/ + +struct Value *Value_retype(struct Value *this, enum ValueType type) { switch (this->type) - { + { case V_INTEGER: - { - switch (type) { - case V_INTEGER: break; - case V_REAL: this->u.real=this->u.integer; this->type=type; break; - case V_VOID: Value_destroy(this); Value_new_VOID(this); break; - default: retypeError(this,type); break; - } - break; - } - case V_REAL: - { - int overflow; - - switch (type) - { - case V_INTEGER: - { - this->u.integer=Value_toi(this->u.real,&overflow); - this->type=V_INTEGER; - if (overflow) + switch (type) { + case V_INTEGER: + break; + case V_REAL: + this->u.real = this->u.integer; + this->type = type; + break; + case V_VOID: Value_destroy(this); - Value_new_ERROR(this,OUTOFRANGE,typestr[V_INTEGER]); + Value_new_VOID(this); + break; + default: + retypeError(this, type); + break; } - break; - } - case V_REAL: break; - case V_VOID: Value_destroy(this); Value_new_VOID(this); break; - default: retypeError(this,type); break; + break; + } + case V_REAL: + { + int overflow; + + switch (type) + { + case V_INTEGER: + { + this->u.integer = Value_toi(this->u.real, &overflow); + this->type = V_INTEGER; + if (overflow) + { + Value_destroy(this); + Value_new_ERROR(this, OUTOFRANGE, typestr[V_INTEGER]); + } + break; + } + case V_REAL: + break; + case V_VOID: + Value_destroy(this); + Value_new_VOID(this); + break; + default: + retypeError(this, type); + break; + } + break; } - break; - } case V_STRING: - { - switch (type) { - case V_STRING: break; - case V_VOID: Value_destroy(this); Value_new_VOID(this); break; - default: retypeError(this,type); break; + switch (type) + { + case V_STRING: + break; + case V_VOID: + Value_destroy(this); + Value_new_VOID(this); + break; + default: + retypeError(this, type); + break; + } + break; } - break; - } case V_VOID: - { - switch (type) { - case V_VOID: break; - default: retypeError(this,type); + switch (type) + { + case V_VOID: + break; + default: + retypeError(this, type); + } + break; } + case V_ERROR: break; + default: + assert(0); } - case V_ERROR: break; - default: assert(0); - } + return this; } -/*}}}*/ -struct String *Value_toString(struct Value *this, struct String *s, char pad, int headingsign, size_t width, int commas, int dollar, int dollarleft, int precision, int exponent, int trailingsign) /*{{{*/ + +struct String *Value_toString(struct Value *this, struct String *s, char pad, + int headingsign, size_t width, int commas, + int dollar, int dollarleft, int precision, + int exponent, int trailingsign) { - size_t oldlength=s->length; + size_t oldlength = s->length; switch (this->type) - { - case V_ERROR: String_appendChars(s,this->u.error.msg); break; + { + case V_ERROR: + String_appendChars(s, this->u.error.msg); + break; case V_REAL: case V_INTEGER: - { - int sign; - struct String buf; - size_t totalwidth=width; + { + int sign; + struct String buf; + size_t totalwidth = width; - String_new(&buf); - if (this->type==V_INTEGER) - { - if (this->u.integer<0) - { - sign=-1; - this->u.integer=-this->u.integer; - } - else if (this->u.integer==0) sign=0; - else sign=1; - } - else - { - if (this->u.real<0.0) - { - sign=-1; - this->u.real=-this->u.real; - } - else if (this->u.real==0.0) sign=0; - else sign=1; - } - switch (headingsign) - { - case -1: - { - ++totalwidth; - String_appendChar(&buf,sign==-1?'-':' '); - break; - } - case 0: - { - if (sign==-1) String_appendChar(&buf,'-'); - break; - } - case 1: - { - ++totalwidth; - String_appendChar(&buf,sign==-1?'-':'+'); - break; - } - case 2: break; - default: assert(0); - } - totalwidth+=exponent; - if (this->type==V_INTEGER) - { - if (precision>0 || exponent) format_double(&buf,(double)this->u.integer,width,precision,exponent); - else if (precision==0) String_appendPrintf(&buf,"%lu.",this->u.integer); - else String_appendPrintf(&buf,"%lu",this->u.integer); - } - else format_double(&buf,this->u.real,width,precision,exponent); - if (commas) - { - size_t digits; - int first; + String_new(&buf); + if (this->type == V_INTEGER) + { + if (this->u.integer < 0) + { + sign = -1; + this->u.integer = -this->u.integer; + } + else if (this->u.integer == 0) + sign = 0; + else + sign = 1; + } + else + { + if (this->u.real < 0.0) + { + sign = -1; + this->u.real = -this->u.real; + } + else if (this->u.real == 0.0) + sign = 0; + else + sign = 1; + } + switch (headingsign) + { + case -1: + { + ++totalwidth; + String_appendChar(&buf, sign = = -1 ? '-' : ' '); + break; + } + case 0: + { + if (sign == -1) + String_appendChar(&buf, '-'); + break; + } + case 1: + { + ++totalwidth; + String_appendChar(&buf, sign == -1 ? '-' : '+'); + break; + } + case 2: + break; + default: + assert(0); + } + totalwidth += exponent; + if (this->type == V_INTEGER) + { + if (precision > 0 || exponent) + format_double(&buf, (double)this->u.integer, width, precision, + exponent); + else if (precision == 0) + String_appendPrintf(&buf, "%lu.", this->u.integer); + else + String_appendPrintf(&buf, "%lu", this->u.integer); + } + else + format_double(&buf, this->u.real, width, precision, exponent); + if (commas) + { + size_t digits; + int first; - first=(headingsign?1:0); - for (digits=first; digits='0' && buf.character[digits]<='9'; ++digits); - while (digits>first+3) - { - digits-=3; - String_insertChar(&buf,digits,','); - } + first = (headingsign ? 1 : 0); + for (digits = first; + digits < buf.length && buf.character[digits] >= '0' && + buf.character[digits] <= '9'; ++digits); + while (digits > first + 3) + { + digits -= 3; + String_insertChar(&buf, digits, ','); + } + } + if (dollar) + { + String_insertChar(&buf, 0, '$'); + } + if (trailingsign == -1) + { + ++totalwidth; + String_appendChar(&buf, sign == -1 ? '-' : ' '); + } + else if (trailingsign == 1) + { + ++totalwidth; + String_appendChar(&buf, sign == -1 ? '-' : '+'); + } + String_size(s, + oldlength + (totalwidth > + buf.length ? totalwidth : buf.length)); + if (totalwidth > buf.length) + memset(s->character + oldlength, pad, + totalwidth - buf.length + dollarleft); + memcpy(s->character + oldlength + + (totalwidth > + buf.length ? (totalwidth - buf.length) : 0) + dollarleft, + buf.character + dollarleft, buf.length - dollarleft); + if (dollarleft) + s->character[oldlength] = '$'; + String_destroy(&buf); + break; } - if (dollar) - { - String_insertChar(&buf,0,'$'); - } - if (trailingsign==-1) - { - ++totalwidth; - String_appendChar(&buf,sign==-1?'-':' '); - } - else if (trailingsign==1) - { - ++totalwidth; - String_appendChar(&buf,sign==-1?'-':'+'); - } - String_size(s,oldlength+(totalwidth>buf.length?totalwidth:buf.length)); - if (totalwidth>buf.length) memset(s->character+oldlength,pad,totalwidth-buf.length+dollarleft); - memcpy(s->character+oldlength+(totalwidth>buf.length?(totalwidth-buf.length):0)+dollarleft,buf.character+dollarleft,buf.length-dollarleft); - if (dollarleft) s->character[oldlength]='$'; - String_destroy(&buf); - break; - } case V_STRING: - { - if (width>0) { - size_t blanks=(this->u.string.lengthu.string.length):0); + if (width > 0) + { + size_t blanks = + (this->u.string.length < + width ? (width - this->u.string.length) : 0); - String_size(s,oldlength+width); - memcpy(s->character+oldlength,this->u.string.character,blanks?this->u.string.length:width); - if (blanks) memset(s->character+oldlength+this->u.string.length,' ',blanks); + String_size(s, oldlength + width); + memcpy(s->character + oldlength, this->u.string.character, + blanks ? this->u.string.length : width); + if (blanks) + memset(s->character + oldlength + this->u.string.length, ' ', + blanks); + } + else + String_appendString(s, &this->u.string); + break; } - else String_appendString(s,&this->u.string); - break; + default: + assert(0); + return 0; } - default: assert(0); return 0; - } + return s; } -/*}}}*/ -struct Value *Value_toStringUsing(struct Value *this, struct String *s, struct String *using, size_t *usingpos) /*{{{*/ -{ - char pad=' '; - int headingsign; - int width=0; - int commas=0; - int dollar=0; - int dollarleft=0; - int precision=-1; - int exponent=0; - int trailingsign=0; - headingsign=(using->length ? 0 : -1); - if (*usingpos==using->length) *usingpos=0; - while (*usingposlength) - { - switch (using->character[*usingpos]) +struct Value *Value_toStringUsing(struct Value *this, struct String *s, + struct String *using, size_t * usingpos) +{ + char pad = ' '; + int headingsign; + int width = 0; + int commas = 0; + int dollar = 0; + int dollarleft = 0; + int precision = -1; + int exponent = 0; + int trailingsign = 0; + + headingsign = (using->length ? 0 : -1); + if (*usingpos == using->length) + *usingpos = 0; + while (*usingpos < using->length) { - case '_': /* output next char */ /*{{{*/ - { - ++(*usingpos); - if (*usingposlength) String_appendChar(s,using->character[(*usingpos)++]); - else + switch (using->character[*usingpos]) { - Value_destroy(this); - return Value_new_ERROR(this,MISSINGCHARACTER); - } - break; - } - /*}}}*/ - case '!': /* output first character of string */ /*{{{*/ - { - width=1; - ++(*usingpos); - goto work; - } - /*}}}*/ - case '\\': /* output n characters of string */ /*{{{*/ - { - width=1; - ++(*usingpos); - while (*usingposlength && using->character[*usingpos]==' ') - { - ++(*usingpos); - ++width; - } - if (*usingposlength && using->character[*usingpos]=='\\') - { - ++(*usingpos); - ++width; - goto work; - } - else - { - Value_destroy(this); - return Value_new_ERROR(this,IOERROR,_("unpaired \\ in format")); - } - break; - } - /*}}}*/ - case '&': /* output string */ /*{{{*/ - { - width=0; - ++(*usingpos); - goto work; - } - /*}}}*/ - case '*': - case '$': - case '0': - case '+': - case '#': - case '.': - { - if (using->character[*usingpos]=='+') - { - headingsign=1; - ++(*usingpos); - } - while (*usingposlength && strchr("$#*0,",using->character[*usingpos])) - { - switch (using->character[*usingpos]) - { - case '$': if (width==0) dollarleft=1; if (++dollar>1) ++width; break; - case '*': pad='*'; ++width; break; - case '0': pad='0'; ++width; break; - case ',': commas=1; ++width; break; - default: ++width; - } - ++(*usingpos); - } - if (*usingposlength && using->character[*usingpos]=='.' ) - { - ++(*usingpos); - ++width; - precision=0; - while (*usingposlength && strchr("*#",using->character[*usingpos])) + case '_': /* output next char */ { ++(*usingpos); - ++precision; - ++width; + if (*usingpos < using->length) + String_appendChar(s, using->character[(*usingpos)++]); + else + { + Value_destroy(this); + return Value_new_ERROR(this, MISSINGCHARACTER); + } + break; } - if (width==1 && precision==0) + case '!': /* output first character of string */ { - Value_destroy(this); - return Value_new_ERROR(this,BADFORMAT); + width = 1; + ++(*usingpos); + goto work; + } + case '\\': /* output n characters of string */ + { + width = 1; + ++(*usingpos); + while (*usingpos < using->length && + using->character[*usingpos] == ' ') + { + ++(*usingpos); + ++width; + } + if (*usingpos < using->length && + using->character[*usingpos] == '\\') + { + ++(*usingpos); + ++width; + goto work; + } + else + { + Value_destroy(this); + return Value_new_ERROR(this, IOERROR, + _("unpaired \\ in format")); + } + break; + } + case '&': /* output string */ + { + width = 0; + ++(*usingpos); + goto work; + } + case '*': + case '$': + case '0': + case '+': + case '#': + case '.': + { + if (using->character[*usingpos] == '+') + { + headingsign = 1; + ++(*usingpos); + } + while (*usingpos < using->length && + strchr("$#*0,", using->character[*usingpos])) + { + switch (using->character[*usingpos]) + { + case '$': + if (width == 0) + dollarleft = 1; + if (++dollar > 1) + ++width; + break; + case '*': + pad = '*'; + ++width; + break; + case '0': + pad = '0'; + ++width; + break; + case ',': + commas = 1; + ++width; + break; + default: + ++width; + } + ++(*usingpos); + } + if (*usingpos < using->length && using->character[*usingpos] == '.') + { + ++(*usingpos); + ++width; + precision = 0; + while (*usingpos < using->length && + strchr("*#", using->character[*usingpos])) + { + ++(*usingpos); + ++precision; + ++width; + } + if (width == 1 && precision == 0) + { + Value_destroy(this); + return Value_new_ERROR(this, BADFORMAT); + } + } + if (*usingpos < using->length && using->character[*usingpos] == '-') + { + ++(*usingpos); + if (headingsign == 0) + headingsign = 2; + trailingsign = -1; + } + else if (*usingpos < using->length && + using->character[*usingpos] == '+') + { + ++(*usingpos); + if (headingsign == 0) + headingsign = 2; + trailingsign = 1; + } + while (*usingpos < using->length && + using->character[*usingpos] == '^') + { + ++(*usingpos); + ++exponent; + } + goto work; + } + default: + { + String_appendChar(s, using->character[(*usingpos)++]); } } - if (*usingposlength && using->character[*usingpos]=='-' ) - { - ++(*usingpos); - if (headingsign==0) headingsign=2; - trailingsign=-1; - } - else if (*usingposlength && using->character[*usingpos]=='+') - { - ++(*usingpos); - if (headingsign==0) headingsign=2; - trailingsign=1; - } - while (*usingposlength && using->character[*usingpos]=='^') - { - ++(*usingpos); - ++exponent; - } - goto work; - } - default: - { - String_appendChar(s,using->character[(*usingpos)++]); - } } - } - work: - Value_toString(this,s,pad,headingsign,width,commas,dollar,dollarleft,precision,exponent,trailingsign); - if ((this->type==V_INTEGER || this->type==V_REAL) && width==0 && precision==-1) String_appendChar(s,' '); - while (*usingposlength) - { - switch (using->character[*usingpos]) +work: + Value_toString(this, s, pad, headingsign, width, commas, dollar, dollarleft, + precision, exponent, trailingsign); + if ((this->type == V_INTEGER || this->type == V_REAL) && width == 0 && + precision == -1) + String_appendChar(s, ' '); + while (*usingpos < using->length) { - case '_': /* output next char */ /*{{{*/ - { - ++(*usingpos); - if (*usingposlength) String_appendChar(s,using->character[(*usingpos)++]); - else + switch (using->character[*usingpos]) { - Value_destroy(this); - return Value_new_ERROR(this,MISSINGCHARACTER); + case '_': /* output next char */ + { + ++(*usingpos); + if (*usingpos < using->length) + String_appendChar(s, using->character[(*usingpos)++]); + else + { + Value_destroy(this); + return Value_new_ERROR(this, MISSINGCHARACTER); + } + break; + } + case '!': + case '\\': + case '&': + case '*': + case '0': + case '+': + case '#': + case '.': + return this; + default: + { + String_appendChar(s, using->character[(*usingpos)++]); + } } - break; - } - /*}}}*/ - case '!': - case '\\': - case '&': - case '*': - case '0': - case '+': - case '#': - case '.': return this; - default: - { - String_appendChar(s,using->character[(*usingpos)++]); - } } - } + return this; } -/*}}}*/ -struct String *Value_toWrite(struct Value *this, struct String *s) /*{{{*/ + +struct String *Value_toWrite(struct Value *this, struct String *s) { switch (this->type) - { - case V_INTEGER: String_appendPrintf(s,"%ld",this->u.integer); break; + { + case V_INTEGER: + String_appendPrintf(s, "%ld", this->u.integer); + break; case V_REAL: - { - double x; - int p=DBL_DIG; - int n,o; - - x=(this->u.real<0.0 ? -this->u.real : this->u.real); - while (x>1.0 && p>0) { x/=10.0; --p; } - o=s->length; - String_appendPrintf(s,"%.*f",p,this->u.real); - n=s->length; - if (memchr(s->character+o,'.',n-o)) { - while (s->character[s->length-1]=='0') --s->length; - if (s->character[s->length-1]=='.') --s->length; - } - break; - } - case V_STRING: /*{{{*/ - { - size_t l=this->u.string.length; - char *data=this->u.string.character; + double x; + int p = DBL_DIG; + int n, o; - String_appendChar(s,'"'); - while (l--) - { - if (*data=='"') String_appendChar(s,'"'); - String_appendChar(s,*data); - ++data; + x = (this->u.real < 0.0 ? -this->u.real : this->u.real); + while (x > 1.0 && p > 0) + { + x /= 10.0; + --p; + } + o = s->length; + String_appendPrintf(s, "%.*f", p, this->u.real); + n = s->length; + if (memchr(s->character + o, '.', n - o)) + { + while (s->character[s->length - 1] == '0') + --s->length; + if (s->character[s->length - 1] == '.') + --s->length; + } + break; } - String_appendChar(s,'"'); - break; + case V_STRING: + { + size_t l = this->u.string.length; + char *data = this->u.string.character; + + String_appendChar(s, '"'); + while (l--) + { + if (*data == '"') + String_appendChar(s, '"'); + String_appendChar(s, *data); + ++data; + } + String_appendChar(s, '"'); + break; + } + default: + assert(0); } - /*}}}*/ - default: assert(0); - } + return s; } -/*}}}*/ -struct Value *Value_nullValue(enum ValueType type) /*{{{*/ + +struct Value *Value_nullValue(enum ValueType type) { - static struct Value integer={ V_INTEGER }; - static struct Value real={ V_REAL }; - static struct Value string={ V_STRING }; - static char n[]=""; - static int init=0; + static struct Value integer = { V_INTEGER }; + static struct Value real = { V_REAL }; + static struct Value string = { V_STRING }; + static char n[] = ""; + static int init = 0; if (!init) - { - integer.u.integer=0; - real.u.real=0.0; - string.u.string.length=0; - string.u.string.character=n; - } + { + integer.u.integer = 0; + real.u.real = 0.0; + string.u.string.length = 0; + string.u.string.character = n; + } switch (type) - { - case V_INTEGER: return &integer; - case V_REAL: return ℜ - case V_STRING: return &string; - default: assert(0); - } - return (struct Value*)0; + { + case V_INTEGER: + return &integer; + case V_REAL: + return ℜ + case V_STRING: + return &string; + default: + assert(0); + } + + return (struct Value *)0; } -/*}}}*/