#include "value.h"
#include "tokentable.h"
#include "main.h"
#include "Structures.h"
#include "command.h"
extern "C"{
#include <math.h>
#include <errno.h>
#include <stdio.h>
  char *crypt (char*, char*);
}
#pragma implementation

#define MAXStrRep_SIZE (SHRT_MAX - 125)   // where the hell is this defined?

#define SET_ERROR(es)                              \
     if (error_string && !(*error_string))         \
       *error_string = new String(es);


int depth_found_at;
/** vs, VS_COUT, VS_UNCOUNT are for memory leak hunting. **/
/** uncomment these to get a shitload of numbers you don\'t understand **/
//int vs;
#define VS_COUNT   /* cout<<(long)this<<" "<<(int)type<<": "<<++vs<<"\n"; */
#define VS_UNCOUNT /* cout<<(long)this<<"    "<<(int)type<<": "<<--vs<<"\n"; */

Value::Value (long inclass, Value* inval){
  type = USER;
  user = new User_Defined (inclass, inval);
  use_count = 1;
  VS_COUNT
}
Value::Value (Value* inclass, Value* inval){
  if (inclass->type != OBJ)
    {err = E_TYPE;
     type = ERR;}
  else
    {if (inclass->obj < 0)
       {err = E_TYPE;
	type = ERR;}
     else
       {user = new User_Defined (inclass->obj , inval);
	type = USER;}}
  use_count = 1;
  VS_COUNT
}
Value::Value(String* instring, Value_Type vtype){
  type = vtype;
  str = instring;
  if (vtype == SYM)
    *str = upcase (*str);
  use_count = 1;
  VS_COUNT
}
Value::Value(char* instring, Value_Type vtype){
  type = vtype;
  str = new String(instring);
  if (vtype == SYM)
    *str = upcase (*str);
  use_count = 1;
  VS_COUNT
}
Value::Value (ifstream* infile){
  char ch;
  if (infile->fail())
    {type = ERR;
     err = E_BAD_FILE;}
  else
    {type = STR;
     str = new String;
     while ((infile->get (ch)) && (str->length() < MAXStrRep_SIZE))
       {*str += ch;
	if (str->length() >= (MAXStrRep_SIZE - 1))
	  {delete str;
	   type = ERR;
	   err = E_LENGTH;
	   return;}}}
  delete infile;
  use_count = 1;
  VS_COUNT
}
Value::Value (FILE* infile){
  int i;
  if (!infile)
    {type = ERR;
     err = E_BAD_FILE;
     return;}
  type = STR;
  str = new String;
  while ((i = getc (infile)) >= 0 &&
	 (str->length() < MAXStrRep_SIZE))
    *str += (char)i;
  fclose (infile);
  use_count = 1;
  VS_COUNT
}
Value::Value(int number, Value_Type vtype){
  type = vtype;
  num = number;
  use_count = 1;
  VS_COUNT
}
Value::Value(Val_List *inlist, Value_Type vtype){
  type = vtype;
  list = inlist;
  use_count = 1;
  VS_COUNT
}
Value::Value(Value *inlist, int begin, int end){
  int i; 
  if (inlist->type != LIST && inlist->type != SUBR && inlist->type != STR)
    {err = E_TYPE;
     type = ERR;
     use_count = 1;
     VS_COUNT
     return;}
  switch (inlist->type)
    {case LIST:  i = inlist->list->length(); break;
    case SUBR:   i = inlist->sub->get_length(); break;
    case STR:    i = inlist->str->length(); break;}
  if (i < begin || i < end || begin < 1 || begin > end)
    {err = E_RANGE;
     type = ERR;
     use_count = 1;
     VS_COUNT
     return;}
  switch (inlist->type)
    {case LIST: case SUBR:
      type = SUBR;
      sub = new Subrange (inlist, begin, end);
      break;
    case STR:
      type = STR;
      str = new String (inlist->str->through (end-1));
      *str = str->from (begin-1);
      break;}
  use_count = 1;
  VS_COUNT
}
Value::Value(Method* inmeth){
  type = MTHD;
  mthd = inmeth;
  use_count = 1;
  VS_COUNT
}
Value::Value(float inreal){
  type = REAL;
  real = inreal;
  use_count = 1;
  VS_COUNT
}

Value::~Value(){
  VS_UNCOUNT
  FREE_VAL;
}

int Value::boolean_val(){
  switch (type)
    {case NUM:
      return num;
    case OBJ:
      return db->obj_exists (obj);
    case REAL:
      return (real != (float)0);
    case LIST:
      return (int)list;
    case STR:
      return str->length();
    case SUBR:
    case SYM:
    case MTHD:
    case USER:
      return 1;
    default:
      return 0;}
}

void Value::tonum (String** error_string){  
  int temp = INT_MIN;
  String err_string;
  switch (type)
    {case LIST: case EXPR: case SYM: case RESERVED: case MTHD: case SUBR:
    case USER:
      err_string = "tonum expects REAL, STRING, NUM, ERR or OBJ ... received ";
      err_string += type_strings[type];
      SET_ERROR(err_string);
      FREE_VAL;
      err = E_TYPE;
      break;
    case REAL:
      num = (int)real;
      type = NUM;
      break;
    case STR:
      sscanf ((char*)str->chars() , "%i" , &temp);
      if (temp == INT_MIN)
	{err_string = "string \"";
	 err_string += *str;
	 err_string += "\" passed to 'tonum' doesn't contain a number";
	 SET_ERROR(err_string);
	 FREE_VAL;
         type = ERR;
	 err = E_DIV_BY_ZERO;}
      else
	{FREE_VAL;
	 type = NUM;
	 num = temp;}
      break;
    case NUM: case ERR: case OBJ:
      type = NUM;
      break;
    default:
      type = ERR;
      err = E_BUG_IN_TONUM;}
}

void Value::toreal (String** error_string){  
  float temp = 0;
  String err_string;
  switch (type)
    {case LIST: case EXPR: case SYM: case RESERVED: case MTHD:
    case ERR: case OBJ: case SUBR: case USER:
      err_string = "toreal expects REAL, NUM or STRING ... received ";
      err_string += type_strings[type];
      SET_ERROR(err_string);
      FREE_VAL;
      err = E_TYPE;
      break;
    case REAL:
      break;
    case NUM:
      real = (float) num;
      type = REAL;
      break;
    case STR:
      sscanf ((char*)str->chars() , "%f" , &temp);
      delete str;
      type = REAL;
      real = temp;
      break;
    default:
      type = ERR;
      err = E_BUG_IN_TOREAL;}
}

void Value::toerr (){
  String err_string;
  switch (type)
    {case NUM:
       if (num < 0)
	 err = -1;
       break;
    case ERR:
       break;
    case MTHD: case LIST: case STR: case SYM: case EXPR:
    case RESERVED: case REAL: case SUBR: case USER:
       FREE_VAL;
       err = E_TYPE;
       break;
    default:
       err = E_BUG_IN_TOERR;}
  type = ERR;
}

void Value::toobj (String** error_string){
  String err_string;
  switch (type)
    {case NUM: case OBJ:
      type = OBJ;  return;
    default:
      err_string = "toobj expects a NUMBER or OBJECT, received a ";
      err_string += type_strings[type];
      SET_ERROR(err_string);
      FREE_VAL;
      err = E_TYPE;    return;}
}

void Value::format (int tab, int columns){
  String *temp_str;
  Val_List *templist;
  int i;
  switch (type)
    {case SUBR:
      subr_to_list();
    case LIST: case EXPR:
      if (!list)
	str = new String (type==LIST ? "'()" : "()");
      else
	{temp_str = list->format (tab, columns);
	 if (type==LIST)  temp_str->prepend("'");
	 delete list;
	 str = temp_str;}
      break;
    case MTHD:
      if (mthd->symlist)
	temp_str = mthd->symlist->tostr();
      else
	temp_str = new String ("()");
      temp_str->prepend ("(method ");
      (*temp_str) += "\n";
      for (i=0 ; i<tab+2 ; i++)
	*temp_str += ' ';
      mthd->expr->format(tab+2);
      *temp_str += *mthd->expr->str;
      (*temp_str) += ")\n";
      FREE_VAL;
      type = STR;
      str = temp_str;
      break;
    default:
      tostr ();}
  type = STR;
}

void Value::tostr (String** error_string){
  char temp[20];
  String *temp_str;
  Val_List *templist;
  switch (type)
    {case SUBR:
      subr_to_list();
    case LIST: case EXPR:
      if (!list)
	str = new String (type==LIST ? "'()" : "()");
      else
	{temp_str = list->tostr();
	 if (type==LIST) temp_str->prepend("'");
	 delete list;
	 str = temp_str;};
      break;
    case RESERVED:
      str = new String (tokentable[reserved].symbol);
      break;
    case STR:
      str->gsub ("\\" , "\001");
      str->gsub ("\"" , "\\\"");
      str->gsub ("\n" , "\\n");
      str->gsub ("\001" , "\\\\");
      str->prepend ("\"");
      *str += "\"";
      break;
    case SYM:
      break;
    case NUM:
      sprintf (temp , "%i", num);
      str = new String (temp);
      break;
    case OBJ:
      sprintf (temp , "#%i", num); 
      str = new String (temp);
      break;
    case ERR:
      sprintf (temp , "!%i", num);
      str = new String (temp);
      break;
    case REAL:
      sprintf (temp , "%.3f" , real);
      str = new String (temp);
      break;
    case USER:
      temp_str = user->tostr();
      FREE_VAL;
      str = temp_str;
      break;
    case MTHD:
      if (mthd->symlist)
	temp_str = mthd->symlist->tostr();
      else
	temp_str = new String ("()");
      temp_str->prepend ("(method ");
      (*temp_str) += " ";
      if (mthd->expr)
	{mthd->expr->tostr();
	 (*temp_str) += *(mthd->expr->str);
	 (*temp_str) += ")";}
      else
	{(*temp_str) += "()";}
      FREE_VAL;
      str = temp_str;
      type = STR;
      break;
    default:
      err = E_BUG_IN_TOSTR;
      type = ERR;
      return;}
  type = STR;
};

void Value::tolist(Val_List* cdr){
  Val_List* templist;
  if (type == SUBR)
    subr_to_list();
  if (cdr)
    templist = new Val_List (copy(), cdr);
  else
    templist = new Val_List (copy());
  FREE_VAL;
  list = templist;
  type = LIST;
}
void Value::toexpr(Val_List* cdr){
  tolist(cdr);
  type = EXPR;
}

void Value::subr_to_list (){
  Val_List* templist;
  if (type == SUBR)
    {templist = sub->copy_full_list();
     delete sub;
     list = templist;
     type = LIST;}
}

Value* Value::grab(){
  use_count++;
  return this;
}
void Value::release(){
  if (this && (! (-- use_count)))
    delete this;
}

Value* Value::copy(){
  Value* temp;
  switch (type)
    {case NUM: case OBJ: case ERR: case RESERVED:
       temp = new Value (num , type);
       break;
    case REAL:
       temp = new Value (real);
       break;
    case STR: case SYM:
       temp = new Value ((new String (*str)), type);
       break;
    case USER:
       temp = new Value (user->get_type(), user->get_val());
       break;
    case LIST: case EXPR:
       if (! list)
	 temp = new Value (list, type);
       else
	 {temp = new Value (list->copy(), type);}
       break;
    case MTHD:
       temp = new Value (mthd->copy());
       break;
    case SUBR:
       temp = sub->copy_full_val();  /** do i need to copy it? hmmm. **/
       /** later, change this to just make another subrange ***/
       break;
     default:
       temp = new Value (E_BUG_IN_COPY , ERR);}
  return temp;
}

Value* Value::ensure_clean(){
  if (use_count > 1)
    {use_count--;
     return copy();}
  if (type == SUBR)
    subr_to_list();
  else if (type == LIST || type == EXPR)
    {list->ensure_clean();}
  return this;
}

void Value::concat (Val_List* inlist){
  if (type == SUBR)
    subr_to_list();
  if (type!= LIST && type != EXPR)
    {FREE_VAL;
     delete inlist;
     err = E_TYPE; return;}
  list->cat(inlist);
}

Value* Value::nth (int i){
  switch (type)
    {case LIST: case EXPR:
      return list->nth(i);
    case SUBR:
      return sub->nth(i);}
  return NULL;
}

Value* Value::car (String** error_string){
  Value* temp;
  String err_string;
  switch (type)
    {case LIST: case EXPR: case SUBR:
      if (temp = nth (1))
	return temp->grab();
      else
	{err_string = "attempting to take 'car' of an empty LIST";
	 SET_ERROR(err_string);
	 return new Value (E_RANGE , ERR);}}
  err_string = "car expects a LIST, received a ";
  err_string += type_strings[type];
  SET_ERROR(err_string);
  return new Value (E_TYPE , ERR);
}

Value* Value::index (Value* i, String** error_string){
  Value* temp;
  String err_string;
  if (i->type != NUM)
    {err_string = "index expects a NUMBER as the first argument, received a ";
     err_string += type_strings[i->type];
     SET_ERROR(err_string);
     return new Value (E_TYPE , ERR);}
  if (type != LIST && type != EXPR && type != SUBR)
    {err_string = "index expects a LIST as the second argument, received a ";
     err_string += type_strings[type];
     SET_ERROR(err_string);
     return new Value (E_TYPE , ERR);}
  temp = nth (i->num);
  if (!temp || i->num < 1)
    {err_string = "attempted to take index ";
     concat_num (err_string, i->num);
     err_string += " of a ";
     concat_num (err_string, list->length());
     err_string += " element list";
     SET_ERROR(err_string);
     return new Value (E_RANGE , ERR);}
  return temp->grab();
}

void Value::tolength (String** error_string){
  int i;
  String err_string;
  if (type != LIST && type != EXPR && type != STR && type != SUBR &&
      type != SYM)
    {err_string = "length expects a LIST, STRING, or SYMBOL, received a ";
     err_string += type_strings[type];
     SET_ERROR(err_string);
     FREE_VAL;
     err = E_TYPE; return;}
  i = get_length();
  FREE_VAL;
  type = NUM;
  num = i;
}

int Value::get_length (){
  int i;
  switch (type)
    {case LIST: case EXPR:
      i = list->length();
      break;
    case STR:
      i = str->length();
      break;
    case SUBR:
      i = sub->get_length();
      break;
    default:
      i = -1;}
  return i;
}

void Value::insert (Value* inval, int position, String** error_string){
  Val_List* templist;
  String err_string;
  if ((type == STR && inval->type != STR) ||
      (type != LIST && type != EXPR && type != STR && type != SUBR))
    {err_string = "insert expects a LIST or STRING, received a ";
     err_string += type_strings[type];
     SET_ERROR(err_string);
     FREE_VAL;
     err = E_TYPE;
     return;}
  switch (type)
    {case SUBR:
      subr_to_list();
    case LIST: case EXPR:
      if ((list->length()+1) < position || position < 1)
	{err_string = "attempting to insert beyond the range of a LIST";
	 SET_ERROR(err_string);
	 FREE_VAL;
	 err = E_RANGE;
	 return;}
      list = list->insert (inval , position);
      return;
    case STR:
      if ((str->length()+1) < position || position < 1)
	{err_string = "attempting to insert beyond the length of a STRING";
	 SET_ERROR(err_string);
	 FREE_VAL;
	 err = E_RANGE;
	 return;}
      cat (str->before(position-1), *inval->str, str->from(position-1), *str);}
}

void Value::increment (){
  if (type != NUM)
    {FREE_VAL;
     err = E_TYPE;
     return;}
  num++;
}

void Value::square_root(String** error_string){
  String err_string;
  switch (type)
    {case NUM:
      real = (float)num;
    case REAL:
      if (real < 0)
	{err_string = "attempted to take the square root of a negative NUMBER";
	 SET_ERROR(err_string);
	 type = ERR;
	 err = E_DIV_BY_ZERO;
	 return;}
      type = REAL;
      real = sqrt(real);
      break;
    default:
      err_string = "square-root expects a NUMBER or REAL, received a ";
      err_string += type_strings[type];
      SET_ERROR(err_string);
      FREE_VAL;
      type = ERR;
      err = E_TYPE;}
}

void Value::add (Value* invar, String** error_string){
  Val_List* templist;
  String* tempstring, err_string;
  if (! ((type == SUBR && invar->type == LIST) ||
	 (type == LIST && invar->type == SUBR)  ||
	 (type == SUBR && invar->type == SUBR)))
    if (invar->type != type || type == OBJ || type == ERR ||
	type == RESERVED || type == SYM || type == EXPR)
      {err_string = "invalid attempt to add/concat a ";
       err_string += type_strings[type];
       err_string += " with a ";
       err_string += type_strings[invar->type];
       SET_ERROR(err_string);
       FREE_VAL;
       err = E_TYPE;
       return;}
  switch (type)
    {case NUM: 
      num =  (invar->num + num);
      break;
    case REAL:
      real += invar->real;
      break;
    case STR:
      if ((str->length() + invar->str->length()) >= MAXStrRep_SIZE)
	{FREE_VAL;
	 err = E_LENGTH;
	 err_string = "concatenating strings would produce a too long string";
	 return;}
      str->prepend (*(invar->str));
      break;
    case SUBR:
      subr_to_list();
    case LIST:
      if (!list)  
	list = ((invar->type == LIST) ? invar->list->copy() :
		invar->sub->copy_full_list());
      else
	{templist = ((invar->type == LIST) ? invar->list->copy() :
		     invar->sub->copy_full_list());
	 if (templist)
	   {templist->cat (list);
	    list = templist;}}
      break;
    default:
      type = ERR;  err = E_BUG_IN_ADD;}
}

void Value::subtract (Value* invar, String** error_string){
  String err_string;
  if (invar->type != type || (type != NUM && type != REAL))
    {err_string = "invalid attempt to subtract a ";
     err_string += type_strings[invar->type];
     err_string += " from a ";
     err_string += type_strings[type];
     SET_ERROR(err_string);
     FREE_VAL;
     err = E_TYPE;
     return;}
  switch (type)
    {case NUM:
      num -= invar->num;
      break;
    case REAL:
      real -= invar->real;
      break;}
}

void Value::div (Value* invar, String** error_string){
  String err_string;
  if (invar->type != type || (type != NUM && type != REAL))
    {err_string = "invalid attempt to divide a ";
     err_string += type_strings[invar->type];
     err_string += " by a ";
     err_string += type_strings[type];
     SET_ERROR(err_string);
     FREE_VAL;
     err = E_TYPE;
     return;}
  switch (type)
    {case NUM:
      if (!invar->num)
	{err_string = "division by zero not allowed";
	 SET_ERROR(err_string);
	 err = E_DIV_BY_ZERO; type = ERR; return;}
      num = num / invar->num;
      break;
    case REAL:
      if (invar->real == (float)0)
	{err_string = "division by zero not allowed";
	 SET_ERROR(err_string);
	 err = E_DIV_BY_ZERO; type = ERR; return;}
      real = real / invar->real;
      break;}  
}
void Value::mod (Value* invar, String** error_string){
  String err_string;
  if (invar->type != type || type != NUM)
    {err_string = "invalid attempt to modulo divide (%) a ";
     err_string += type_strings[invar->type];
     err_string += " by a ";
     err_string += type_strings[type];
     err_string += " (both arguments must be NUMBERS)";
     SET_ERROR(err_string);
     FREE_VAL;
     err = E_TYPE;
     return;}
  if (!invar->num)
    {err_string = "modulo division by zero not allowed";
     SET_ERROR(err_string); 
     err = E_DIV_BY_ZERO; type = ERR; return;}
  num = num % invar->num;
}

void Value::mul (Value* invar, String** error_string){
  String err_string;
  if (invar->type != type || (type != NUM && type != REAL))
    {err_string = "invalid attempt to multiply a ";
     err_string += type_strings[invar->type];
     err_string += " by a ";
     err_string += type_strings[type];
     SET_ERROR (err_string);
     FREE_VAL;
     err = E_TYPE;
     return;}
  switch (type)
    {case NUM:
      num = num * invar->num;
      break;
    case REAL:
      real = real * invar->real;
      break;}  
}


int Value::compare (Value* inval){
  if (type == SUBR)
    subr_to_list();
  if (inval->type == SUBR)
    inval->subr_to_list();
  if (type != inval->type)
    {return INT_MAX;}
  switch (type)
    {case NUM: case ERR: case OBJ: case RESERVED:
       return (num - inval->num);
    case REAL:     /** compares after truncating past two digits **/
       return (int)((inval->num * 100 - num * 100) / 100);
    case STR:
       return (fcompare (*str , *(inval->str)));
    case SYM:
       return (fcompare (*sym , *(inval->sym)));
    case USER:
       return INT_MAX;
    case LIST:
       return (list->compare (inval->list));}
  return INT_MAX;
}

void Value::equal (Value* inval, String** error_string){
  int ret;
  String err_string;
  ret = compare (inval);
  if (ret == INT_MAX)
    {err_string = "invalid attempt to check equality (=) between a ";
     err_string += type_strings[inval->type];
     err_string += " and a ";
     err_string += type_strings[type];
     SET_ERROR (err_string);
     FREE_VAL;
     type = ERR;
     err = E_INCOMPATIBLE_TYPES;}
  else
    {FREE_VAL;
     if (!ret)
       {type = NUM;
	num = 1;}
     else
       {type = LIST;
	list = NULL;}}
}

void Value::less_than (Value* inval, String** error_string){
  int ret;
  String err_string;
  ret = compare (inval);
  if (ret == INT_MAX)
    {err_string = "invalid attempt to compare (<) a ";
     err_string += type_strings[inval->type];
     err_string += " and a ";
     err_string += type_strings[type];
     SET_ERROR (err_string);
     FREE_VAL;
     type = ERR;  err = E_INCOMPATIBLE_TYPES;}
  else
    {FREE_VAL;
     if (ret < 0 && ret > INT_MIN)
       {type = NUM;
	num = 0 - ret;}
     else
       {type = LIST;
	list = NULL;}}
}

void Value::less_than_equal (Value* inval, String** error_string){
  int ret;
  String err_string;
  ret = compare (inval);
  if (ret == INT_MAX)
    {err_string = "invalid attempt to compare (<=) a ";
     err_string += type_strings[inval->type];
     err_string += " and a ";
     err_string += type_strings[type];
     SET_ERROR (err_string);
     FREE_VAL;
     type = ERR;  err = E_INCOMPATIBLE_TYPES;}
  else
    {FREE_VAL;
     if (ret <= 0 && ret > INT_MIN)
       {type = NUM;
	num = 1;}
     else
       {type = LIST;
	list = NULL;}}
}


void Value::greater_than_equal (Value* inval, String** error_string){
  int ret;
  String err_string;
  ret = compare (inval);
  if (ret == INT_MAX)
    {err_string = "invalid attempt to compare (<=) a ";
     err_string += type_strings[inval->type];
     err_string += " and a ";
     err_string += type_strings[type];
     SET_ERROR (err_string);
     FREE_VAL;
     type = ERR;  err = E_INCOMPATIBLE_TYPES;}
  else
    {FREE_VAL;
     if (ret >= 0 && ret > INT_MIN)
       {type = NUM;
	num = 1;}
     else
       {type = LIST;
	list = NULL;}}
}

void Value::not (String** error_string){
  long temp = 1;
  String err_string;
  Value_Type ntype = NUM;
  switch (type)
    {case ERR:
      break;
    case SYM: case USER: case SUBR:
      FREE_VAL;
      type = LIST;
      list = NULL;
      return;
    case STR:
      if (str->length())
	{FREE_VAL;
	 type = LIST;
	 list = NULL;
         return;}
      break;
    case LIST:
      if (list)
	{FREE_VAL;
	 type = LIST;
	 list = NULL;
         return;}
      break;
    case NUM:
      if (num)
	{FREE_VAL;
	 type = LIST;
	 list = NULL;
         return;}
      break;
    default:
      err_string = "invalid type received by not: ";
      err_string += type_strings[type];
      SET_ERROR (err_string);
      ntype = ERR;   temp = E_TYPE;}
  FREE_VAL;
  type = ntype;
  num = temp;
}

void Value::greater_than (Value* inval, String** error_string){
  int ret;
  String err_string;
  ret = compare (inval);
  if (ret == INT_MAX)
    {err_string = "invalid attempt to compare (>) a ";
     err_string += type_strings[inval->type];
     err_string += " and a ";
     err_string += type_strings[type];
     SET_ERROR (err_string);
     FREE_VAL;
     type = ERR;  err = E_INCOMPATIBLE_TYPES;}
  else
    {FREE_VAL;
     if (ret > 0)
       {type = NUM;
	num = 0 - ret;}
     else
       {type = LIST;
	list = NULL;}}
}

Value* get_time(){
  return new Value (time ((time_t*)0));
}
Value* get_random(){
  return new Value (rand ());
}
Value* reg_split(Value* regstring, Value* bigstring){
  String subs;
  Regex* rx;
  int i;
  Val_List* temp_list = NULL;
//  cout << "ENTERING REG_SPLIT [" << *(regstring->str) << "] ["
//    << *(bigstring->str) << "]\n";
  if (! valid_regexp (regstring->str))
    {return new Value (E_INVALID_REGEXP , ERR);}
  rx = new Regex (regstring->str->chars());
  if ((! bigstring->str->length())|| ((i = bigstring->str->index (*rx)) < 0))
    return new Value ((Val_List*)NULL);
  subs = bigstring->str->through (*rx);
  if (!i && !subs.length())
    return new Value ((Val_List*)NULL);
  temp_list = new Val_List
    (new Value (new String (bigstring->str->after (subs))));
  temp_list = new Val_List
    (new Value (new String (subs.from(i))), temp_list);
  temp_list = new Val_List
    (new Value (new String (subs.before (i))), temp_list);
  delete rx;
//  cout << "EXITTING REG_SPLIT\n";
  return new Value (temp_list);
}

char* Value::pack_value (char* buf){
  long i;
  *buf = (char) type;
  buf++;
  switch (type)
    {case NUM: case OBJ: case ERR: case RESERVED:
      PACK_INT(buf , num);
      buf += sizeof (long);
      break;
    case STR: case SYM:
      strcpy (buf , str->chars());
      buf += str->length() + 1;
      break;
    case REAL:
      PACK_FLOAT(buf, real);
      buf += sizeof (float);
      break;
    case MTHD:
      buf = mthd->pack_method (buf);
      break;
    case USER:
      i = user->get_type();
      PACK_INT (buf, i);
      buf = user->get_val()->pack_value (buf + sizeof (long));
      break;
    case SUBR:
      subr_to_list();
      *(buf-1) = (char) LIST;
    case LIST: case EXPR:
      if (list)
	{i = list->length();
	 PACK_INT(buf, i);
	 buf += sizeof (long);
	 buf = list->pack_list (buf);}
      else
	{i = 0;
	 PACK_INT(buf , i);
	 buf += sizeof (float);}
      break;
    default:
      cout << "ERROR in packing value ... invalid type found";}
  return buf;
}

Value* unpack_value (char** temp_bufptr){
  char* buf, type;
  Value* retval;
  Val_List* cdr;
  String* tempstring;
  long i, j, k;
  float flt;
  buf = *temp_bufptr;
  type = (*buf);
  buf++;
  switch (type)
    {case STR: case SYM:
      tempstring = new String (buf);
      buf += tempstring->length() + 1;
      retval = new Value (tempstring, (Value_Type)type);
      break;
    case NUM: case OBJ: case ERR: case RESERVED:
      UNPACK_INT (buf , i);
      retval = new Value (i , (Value_Type)type);
      buf += sizeof (long);
      break;
    case USER:
      UNPACK_INT (buf, i);
      buf += sizeof(long);
      retval = new Value (i, unpack_value(&buf));
      break;
    case REAL:
      UNPACK_FLOAT (buf, flt);
      buf += sizeof (float);
      retval = new Value (flt);
      break;
    case MTHD:
      UNPACK_INT (buf, i);
      buf += sizeof (long);
      for (j = 0 , cdr = NULL ; j<i ; j++)
	{tempstring = new String (++buf);
	 k = tempstring->length();
	 cdr = new Val_List (new Value (tempstring, SYM), cdr);
	 buf += tempstring->length() + 1;}
      retval = new Value (new Method (cdr , unpack_value (&buf)));
      break;
    case LIST: case EXPR:
      UNPACK_INT (buf, i);
      buf += sizeof (long);
      for (j = 0 , cdr = NULL ; j<i ; j++)
	cdr = new Val_List (unpack_value (&buf), cdr);
      retval = new Value (cdr , (Value_Type)type);
      break;
    default:
      cout << "ERROR in unpacking value ... invalid type found.\n";
      retval = NULL;}
  *temp_bufptr = buf;
  return retval;
}


void Value::encryption (String** error_string){
  char *temp, salt[3];
  String err_string;
  if (type != STR)
    {err_string = "crypt requires a STRING, received a ";
     err_string += type_strings[type];
     SET_ERROR (err_string);
     FREE_VAL;
     err = E_TYPE;
     return;}
  salt[2] = '\0';
  if (str->length() < 2)
    {salt[0] = 'A';
     salt[1] = 'A';}
  else
    {salt[0] = str->chars()[0];
     salt[1] = str->chars()[1];}
  temp = crypt ((char*)str->chars(), salt);
  delete str;
  str = new String (temp);
}

int Value::ok_clause(){
  switch (type)
    {case STR:
      return 1;
    case SYM:
      return is_command_constant (sym);
    case LIST: case EXPR:
      return list->ok_clause();}  
  return 0;
}

String* Value::command_match (String& pattern){
  String* tempstring;
  int nonspace = 0;
  if (type != STR || pattern.index (*str) != 0)
    while (pattern.index(" ", nonspace) == nonspace)
      nonspace++;
  switch (type)
    {case STR:
      if (str->length() == 0)
	return new String;
      if (pattern.index(*str, nonspace) == nonspace)
	return new String (*str);
      break;
    case SYM:
      if (tempstring = match_command_constant (sym, pattern.from(nonspace)))
	return tempstring;
      break;
    case LIST: case EXPR:
      if (list->length() && list->elem->get_type() == RESERVED)
	switch (list->elem->reserved)
	  {case OR:
	    return list->next->command_match_OR (pattern);
	  case BEFORE:
	    return list->next->elem->command_match_BEFORE
	      (pattern.from(nonspace));}
      break;
    default:
      break;}
  return NULL;    
}

String* Value::command_match_BEFORE (String& pattern){
  String* retval;
  Regex* re;
  int qpos = 0, spos;
  if (pattern.index("\"") == 0)
    if ((qpos = pattern.index("\"", 1)) > -1)
      qpos++;
  spos = -1;
  switch (type)
    {case STR:
      spos = pattern.index (*str, qpos);
      break;
    case SYM:
      if (re = get_command_constant (sym))
	spos = pattern.index (*re, qpos);
    default:
      break;}
  if (spos > -1)
    {retval = new String (pattern.before (spos));
     while (retval->length() &&
	    retval->elem(retval->length()-1) == ' ')
       *retval = retval->before (retval->length()-1);
     return retval;}
  return NULL;
}

Value* Value::implode (Value* separator, String** error_string){
  String err_string, *retval=NULL;
  Val_List* listptr;
  retval = new String;
  for (listptr = list ;
       listptr && (listptr->elem->get_type() == STR)
       ; listptr = listptr->next)
    {*retval += *listptr->elem->str;
     if (listptr->next)
       *retval += *separator->str;}
  if (!listptr)
    return new Value (retval);
  err_string = "you can only implode a list of strings.";
  SET_ERROR (err_string);
  delete retval;
  return new Value (E_TYPE , ERR);
}


int Value::obj_val(){
  return (type==OBJ ? obj : -1);
}

void Value::print_val (){      /** converts to string first ... **/
  int i;
  format (0, 75);
  cout << *str;
}


/**************************************************************
*******  class Value_Stack declarations: **********************
***************************************************************/

Value_Stack::Value_Stack(int isize){
  allocated = isize;
  vstack = new Value* [isize];
  scope_level = new int [isize];
  current_scope = 0;
  depth = 0;
  scope_depth = 0;
};

Value_Stack::~Value_Stack(){
  while (depth)
    vstack [--depth] -> release();
  delete scope_level;
  delete vstack;
};

void Value_Stack::push_val (Value* someval){
  scope_level[depth] = current_scope;
  vstack[depth++] = someval->grab();
  scope_depth++;
  if (depth == allocated)
    grow();
}

Value* Value_Stack::pop_val (){
  if (depth)
    {scope_depth--;
     return vstack[--depth];}    /**** caller is responsible for deleting ****/
  else
    {return new Value (E_STACK_UN, ERR);}
}

Value* Value_Stack::peek (){
  if (depth)
    {return vstack[depth-1];}
  else
    {return new Value (E_STACK_UN, ERR);}
}

void Value_Stack::push_scope (void){
  current_scope++;
  scope_depth = 0;
}
void Value_Stack::pop_scope (void){
  int i;
  while (scope_depth)
    (pop_val())->release();
  current_scope--;  
  for (i=depth-1 ; i>=0 && scope_level [i] == current_scope ;
       i-- , scope_depth++);
}

Value* Value_Stack::peek_scope_bottom (void){
  if (!scope_depth)
    return (Value*)NULL;
  return vstack [depth - scope_depth];
}

Value** Value_Stack::pointer_scope_bottom (void){
  if (!scope_depth)
    return (Value**)NULL;
  return &(vstack [depth - scope_depth]);
}

Value* Value_Stack::highest_not_anon (Value* anon){
  int i;
  for (i=depth ; i ;)
    if (vstack[--i] != anon)
      {depth_found_at = i;
       return vstack[i];}
  depth_found_at = -1;
  return NULL;
}

void Value_Stack::grow (int by){
  Value** temp_vstack = new Value* [allocated + by];
  int* temp_scope_level = new int [allocated+by];
  int i;
  for (i=0 ; i<depth ; i++)
    {temp_vstack[i] = vstack[i];
     temp_scope_level[i] = scope_level[i];}
  allocated += by;
  delete vstack;
  delete scope_level;
  vstack = temp_vstack;
  scope_level = temp_scope_level;
}


void concat_num (String& instring, int num){
  char charblock[12];
  sprintf (charblock , "%d", num);
  instring += charblock;
}