//
// Copyright (C) 1991 Texas Instruments Incorporated.
//
// Permission is granted to any individual or institution to use, copy, modify,
// and distribute this software, provided that this complete copyright and
// permission notice is maintained, intact, in all copies and supporting
// documentation.
//
// Texas Instruments Incorporated provides this software "as is" without
// express or implied warranty.
//
// Created: LGO 05/19/89 -- Initial design and implementation
// Updated: MBN 09/18/89 -- Changed package name to uppercase

#include <cool/Generic.h>

#if GENERIC_TYPECHECK

#ifndef C_STRINGH
#if defined(DOS)		// If String support not yet defined,
extern "C" {
#include <string.h>		// Include standard string header file
}
#else
#include <string.h>		// Include standard string header file
#endif
#define C_STRINGH
#endif

// lsubstr -- find last occurence of substring, string2, in string, string1.
//
char *lsubstr(register char *string1, char *string2)
{
     register char cp1, cp2;
     register char *pos = string1;

     while (*string1)         /* FOR EACH STRING IN SOURCE STRING */
     {
         register const char *cmp = string2;

         while (((cp1 = *string1++) == (cp2 = *cmp++)) && cp1);
	 if (cp2 == 0 && cp1 == 0) return pos;
	 string1 = ++pos;
     }
     return NULL;
}

MACRO PRINT_VALUE (os, type, value) {
  if ((*(int*) value) == NULL)             os << "0";
  else if (lsubstr(type,"int*"))	   os << *(int**) value;
  else if (lsubstr(type,"unsigned int"))   os << *(unsigned int*) value;
  else if (lsubstr(type,"int"))		   os << *(int*) value;
  else if (lsubstr(type,"unsigned char*")) os << *(unsigned char**) value;
  else if (lsubstr(type,"char*"))	   os << *(char**) value;
  else if (lsubstr(type,"unsigned char"))  os << *(unsigned char*) value;
  else if (lsubstr(type,"char"))	   os << *(char*) value;
  else if (lsubstr(type,"double*"))	   os << *(double**) value;
  else if (lsubstr(type,"double"))	   os << *(double*) value;
  else if (lsubstr(type,"long*"))	   os << *(long**) value;
  else if (lsubstr(type,"unsigned long"))  os << *(unsigned long*) value;
  else if (lsubstr(type,"long"))	   os << *(long*) value;
  else if (lsubstr(type,"float"))	   os << *(float*) value;
  else if (lsubstr(type,"float*"))	   os << *(float**) value;
  else if (lsubstr(type,"short*"))	   os << *(short**) value;
  else if (lsubstr(type,"unsigned short")) os << *(unsigned short*) value;
  else if (lsubstr(type,"short"))	   os << *(short*) value;
  else if (lsubstr(type,"Generic*"))	   os << *(Generic**) value;
  else if (lsubstr(type,"Generic"))	   os << *(Generic*) value;
  else					   os <<  (void*)*(int*) value;
}

// describe_slot -- Slot_Mapper function to describe a specified slot
//                  on a specified stream.
//
static Boolean
describe_slot (Generic* obj, char* slot, void* value, char* type, void* rock) {
  ostream& os = *(ostream*) rock;
  os << form("%15s::%-15s %-30s ",  obj->type_of()->name(), slot, type);
  PRINT_VALUE(os, type, value);                     
  os << "\n";
  return FALSE;
}

// describe -- Display all slots of this object in  some "raw" format.
// 
void Generic::describe (ostream& os) {
  os << form("%17s%-15s %-30s %s\n", "Slot","","Type","Value");
  os << form("%17s%-15s %-30s %s\n", "----","","----","-----");
  this->map_over_slots(&describe_slot, &os);
}
#endif
