/* #includes */ /*{{{C}}}*//*{{{*/
#undef  _POSIX_SOURCE
#define _POSIX_SOURCE   1
#undef  _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 2

#include "config.h"

#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <float.h>
#ifdef HAVE_GETTEXT
#include <libintl.h>
#define _(String) gettext(String)
#else
#define _(String) String
#endif
#include <limits.h>
#include <math.h>
/* Buggy on some systems */
#if 0
#ifdef HAVE_TGMATH_H
#include <tgmath.h>
#endif
#else
extern long int lrint(double x);
#endif
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "error.h"
#include "value.h"

#ifdef USE_DMALLOC
#include "dmalloc.h"
#endif
/*}}}*/

/* variables */ /*{{{*/
static const char *typestr[]=
{
  (const char*)0,
  (const char*)0,
  "integer",
  (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]=
{
  { 0, 0,       0,         0,       0,       0,        0       },
  { 0, V_ERROR, V_ERROR,   V_ERROR, V_ERROR, V_ERROR,  V_ERROR },
  { 0, V_ERROR, V_INTEGER, V_ERROR, V_REAL,  V_ERROR,  V_ERROR },
  { 0, V_ERROR, V_ERROR,   V_ERROR, V_ERROR, V_ERROR,  V_ERROR },
  { 0, V_ERROR, V_REAL,    V_ERROR, V_REAL,  V_ERROR,  V_ERROR },
  { 0, V_ERROR, V_ERROR,   V_ERROR, V_ERROR, V_STRING, V_ERROR },
  { 0, V_ERROR, V_ERROR,   V_ERROR, V_ERROR, V_ERROR,  V_ERROR }
};

#ifndef HAVE_LRINT
long int lrint(double d)
{
  return d;
}
#endif

static void format_double(struct String *buf, double value, int width, int precision, int exponent) /*{{{*/
{
  if (exponent)
  {
    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);
  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;

      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_trunc(double d) /*{{{*/
{
  return (d<0.0?ceil(d):floor(d));
}
/*}}}*/
double Value_round(double d) /*{{{*/
{
  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 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);
  return n;
}
/*}}}*/
double Value_vald(const char *s, char **end, int *overflow) /*{{{*/
{
  double d;

  errno=0;
  d=strtod(s,end);
  *overflow=(errno==ERANGE);
  return d;
}
/*}}}*/

struct Value *Value_new_NIL(struct Value *this) /*{{{*/
{
  assert(this!=(struct Value*)0);
  this->type=V_NIL;
  return this;
}
/*}}}*/
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);
  va_end(ap);
  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) /*{{{*/
{
  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) /*{{{*/
{
  assert(this!=(struct Value*)0);
  this->type=V_REAL;
  this->u.real=n;
  return this;
}
/*}}}*/
struct Value *Value_new_STRING(struct Value *this) /*{{{*/
{
  assert(this!=(struct Value*)0);
  this->type=V_STRING;
  String_new(&this->u.string);
  return this;
}
/*}}}*/
struct Value *Value_new_VOID(struct Value *this) /*{{{*/
{
  assert(this!=(struct Value*)0);
  this->type=V_VOID;
  return this;
}
/*}}}*/
struct Value *Value_new_null(struct Value *this, enum ValueType type) /*{{{*/
{
  assert(this!=(struct Value*)0);
  switch (type)
  {
    case V_INTEGER:
    {
      this->type=V_INTEGER;
      this->u.integer=0;
      break;
    }
    case V_REAL:
    {
      this->type=V_REAL;
      this->u.real=0.0;
      break;
    }
    case V_STRING:
    {
      this->type=V_STRING;
      String_new(&this->u.string);
      break;
    }
    case V_VOID:
    {
      this->type=V_VOID;
      break;
    }
    default: assert(0);
  }
  return 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);
  }
  return -1;
}
/*}}}*/
void Value_destroy(struct Value *this) /*{{{*/
{
  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;
      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) /*{{{*/
{
  switch (this->type)
  {
    case V_INTEGER:
    case V_REAL:
    {
      break;
    }
    case V_STRING:
    {
      Value_destroy(this);
      Value_new_ERROR(this,INVALIDUOPERAND);
      break;
    }
    default: assert(0);
  }
  return this;
}
/*}}}*/
struct Value *Value_uneg(struct Value *this, int calc) /*{{{*/
{
  switch (this->type)
  {
    case V_INTEGER:
    {
      if (calc) this->u.integer=-this->u.integer;
      break;
    }
    case V_REAL:
    {
      if (calc) this->u.real=-this->u.real;
      break;
    }
    case V_STRING:
    {
      Value_destroy(this);
      Value_new_ERROR(this,INVALIDUOPERAND);
      break;
    }
    default: assert(0);
  }
  return this;
}
/*}}}*/
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;
      }
      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 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) /*{{{*/
{
  switch (this->type)
  {
    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) /*{{{*/
{
  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]));
}
/*}}}*/
static void retypeError(struct Value *this, enum ValueType to) /*{{{*/
{
  enum ValueType thisType=this->type;

  assert(typestr[thisType]);
  assert(typestr[to]);
  Value_destroy(this);
  Value_new_ERROR(this,TYPEMISMATCH1,_(typestr[thisType]),_(typestr[to]));
}
/*}}}*/
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)
          {
            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;
    }
    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;
      }
      break;
    }
    case V_VOID:
    {
      switch (type)
      {
        case V_VOID: break;
        default: retypeError(this,type);
      }
      break;
    }
    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) /*{{{*/
{
  size_t oldlength=s->length;

  switch (this->type)
  {
    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;

      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<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;
    }
    case V_STRING:
    {
      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);
      }
      else String_appendString(s,&this->u.string);
      break;
    }
    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 (*usingpos<using->length)
  {
    switch (using->character[*usingpos])
    {
      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 '!': /* output first character of string */ /*{{{*/
      {
        width=1;
        ++(*usingpos);
        break;
      }
      /*}}}*/
      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)++]);
      }
    }
  }
  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)
  {
    switch (using->character[*usingpos])
    {
      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)++]);
      }
    }
  }
  return this;
}
/*}}}*/
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_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;
      
      String_appendChar(s,'"');
      while (l--)
      {
        if (*data=='"') String_appendChar(s,'"');
        String_appendChar(s,*data);
        ++data;
      }
      String_appendChar(s,'"');
      break;
    }
    /*}}}*/
    default: assert(0);
  }
  return s;
}
/*}}}*/
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;

  if (!init)
  {
    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 &real;
    case V_STRING: return &string;
    default: assert(0);
  }
  return (struct Value*)0;
}
/*}}}*/
