/****************************************************************************
**
**  Name:  DEMANGLE.C
**
**  Description:
**      Translate mangling string to expression string.
**
**  Status:  CODED
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/
                       /****************************
			*                          *
                        *       INCLUDE FILES      *
			*                          *
			****************************/
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <time.h>
#include <io.h>
#include <memory.h>

#ifndef __HEAP__
#include "heap.h"
#endif

#ifndef __LDMANGLE__
#include "ldmangle.h"
#endif

#ifndef __LDR__
#include "ldr.h"
#endif

		       /****************************
			*                          *
			*     LOCAL DEFINITIONS    *
			*                          *
			****************************/
extern U32 symtab_offset, symtab_size;
extern U32 strtab_offset, strtab_size;
struct mypara pa[10];    // define a parameter structure for mangling string
// create operator table
struct optype op[] = {
 { "aa" , 2, "&&"       } ,
 { "aad", 3, "&="       } ,
 { "ad" , 2, "&"        } ,
 { "adv", 3, "/="       } ,
 { "aer", 3, "^="       } ,
 { "als", 3, "<<="      } ,
 { "amd", 3, "%="       } ,
 { "ami", 3, "-="       } ,
 { "amu", 3, "*="       } ,
 { "aor", 3, "|="       } ,
 { "apl", 3, "+="       } ,
 { "ars", 3, ">>="      } ,
 { "as" , 2, "="        } ,
 { "cl" , 2, "()"       } , //Hera 1/8/97
 { "cm" , 2, ","        } ,
 { "co" , 2, "~"        } ,
 { "da" , 2, "delete[]" } ,
 { "dl" , 2, "delete"   } ,
 { "dv" , 2, "/"        } ,
 { "eq" , 2, "=="       } ,
 { "er" , 2, "^"        } ,
 { "ge" , 2, ">="       } ,
 { "gt" , 2, ">"        } ,
 { "le" , 2, "<="       } ,
 { "ls" , 2, "<<"       } ,
 { "lt" , 2, "<"        } ,
 { "md" , 2, "%"        } ,
 { "mi" , 2, "-"        } ,
 { "ml" , 2, "*"        } ,
 { "mm" , 2, "--"       } ,
 { "na" , 2, "new[]"    } ,
 { "ne" , 2, "!="       } ,
 { "nt" , 2, "!"        } ,
 { "nw" , 2, "new"      } ,
 { "oo" , 2, "||"       } ,
 { "or" , 2, "|"        } ,
 { "pl" , 2, "+"        } ,
 { "pp" , 2, "++"       } ,
 { "rm" , 2, "->*"      } ,
 { "rf" , 2, "->"       } ,
 { "rs" , 2, ">>"       } ,
 { "vc" , 2, "[]"       } //Hera 1/8/97
};

int   IsClass;    // flag for a class type
int   IsMember;   // flag for a member type
int   StrPtr;     // variable that indicates the pointer of the mangling string
int   ParPtr;     // variable that indicates the pointer of the parameter struct
int   SyxErr;     // flag for a mangling string format
const OPMAX = 42; // define operator number

// function = margu mclas<mstru>::mfunc mpref(mpara)
CHAR *FuncStr;  // function string
CHAR *MangStr;  // mangle string
CHAR *margu;    // argument string
CHAR *mclas;    // class string
CHAR *mstru;    // structure string
CHAR *mpref;    // prefix string
CHAR *mfunc;    // function string
CHAR *mpara;    // parameter string
CHAR *mtype;    // type string
CHAR *tmpc;


		       /****************************
			*                          *
			*     LOCAL PROTOTYPES     *
			*                          *
			****************************/
RETCODE PRIVATE LdmangleDiabGetCode(VOID) ;
RETCODE PRIVATE LdmangleDiabGetType(CHAR *mtype) ;
RETCODE PRIVATE LdmangleDiabGetClass(VOID) ;
RETCODE PRIVATE LdmangleDiabGetPrefix(VOID) ;
RETCODE PRIVATE LdmangleDiabGetPara(VOID) ;
RETCODE PRIVATE LdmangleDiabConcat(VOID) ;

		       /****************************
			*                          *
                        *      EXECUTABLE CODE     *
			*                          *
			****************************/
/******************************************************************************
**   LdmangleDiabGetPrefix
******************************************************************************/
RETCODE LdmangleDiabGetPrefix(VOID) {
  char tmp[3];
  int j;

  j = 0;
  StrPtr++;
  if (MangStr[StrPtr] != '_') SyxErr = 1;
  else {
    StrPtr++;
    while (MangStr[StrPtr] != '_') {
      if (MangStr[StrPtr] == '\0') {
	SyxErr = 1;
	break;
      }
      tmp[j] = MangStr[StrPtr];
      StrPtr++;
      j++;
    }
    tmp[j] = '\0';
    StrPtr++;
    if (!strncmpi(tmp, "ct", 2)) {
      strcpy(mpref, " ");
      IsClass = 1;
    } else if (!strncmpi(tmp, "dt", 2)) {
      strcpy(mpref, "~");
     IsClass = 1;
    /*} else if (!strncmpi(tmp, "vc", 2)) {
      strcpy(mpref, "[]"); //Hera 1/8/98
    } else if (!strncmpi(tmp, "cl", 2)) {
      strcpy(mpref, "()");//Hera 1/8/98 refer to the Diab Data Page98*/
    } else {
      for (j = 0; j < OPMAX; j++) {
	if (!strncmpi(tmp, op[j].code, op[j].size)) {
	  strcpy(mpref, "operator ");
	  strcat(mpref, op[j].name);
	  break;
	}
      }
    }
  }
  if ((MangStr[StrPtr] != '_') || (*mpref == '\0')) SyxErr = 1;
  else StrPtr++;
  return(GOOD);
}   /*  LdmangleDiabGetPrefix function  */

/******************************************************************************
**   LdmangleDiabGetFunc : get function header
******************************************************************************/
RETCODE LdmangleDiabGetFunc(VOID) {
  char tmp[50];
  int j = 0;

  while (MangStr[StrPtr] != '\0') {
    if (MangStr[StrPtr] == '_' && MangStr[StrPtr + 1] == '_') break;
    else {
      tmp[j] = MangStr[StrPtr];
      StrPtr++;
      j++;
    }
    tmp[j] = '\0';
  }
  strcpy(mfunc, tmp);
  StrPtr++;
  if ((MangStr[StrPtr] != '_') || (MangStr[StrPtr - 1] == '\0')) SyxErr = 1;
  StrPtr++;
  return(GOOD);
}  /*  LdmangleDiabGetFunc function  */

/******************************************************************************
**   LdmangleDiabGetType : get name
******************************************************************************/
RETCODE LdmangleDiabGetType(CHAR *mtype) {
  int j, N = 0;

  if (MangStr[StrPtr] == 'B') StrPtr++;
  if (!isdigit(MangStr[StrPtr])) SyxErr = 1;
  while (isdigit(MangStr[StrPtr])) {
    N = N * 10 + (MangStr[StrPtr] - 48);
    StrPtr++;
  }
  for (j = 0; j < N; j++) {
    if (MangStr[StrPtr] != '\0') {
      *(mtype+j) = MangStr[StrPtr];
      StrPtr++;
    } else SyxErr = 1;
  }
  *(mtype+j) = '\0';
  if (N > 0) StrPtr--;
  return(GOOD);
}  /* LdmangleDiabGetType function  */


/******************************************************************************
**   LdmangleDiabGetClass : get class name
******************************************************************************/
RETCODE LdmangleDiabGetClass(VOID) {
  char tmp[50];
  char tmps[50];
  int j, k, N;
  int IsTemplate;

  IsTemplate = 0;
  N = 0;
  while (isdigit(MangStr[StrPtr])) {
    N = N * 10 + (MangStr[StrPtr] - 48);
    StrPtr++;
  }
  for (j = 0; j < N; j++) {
    if (MangStr[StrPtr] != '\0') {
      tmp[j] = MangStr[StrPtr];
      StrPtr++;
    } else SyxErr = 1;
  }
  tmp[j] = '\0';
  tmpc[0] = '\0';
  tmps[0] = '\0';
  j = 0;
  k = 0;
  while (tmp[j] != '\0') {
    if (tmp[j] == '_') break;
    k++;
    j++;
  }
  if ((tmp[k+1] == '_') && (tmp[k+2] == 't')) {
    IsTemplate = 1;
    for (j = 0; j < k; j++) tmpc[j] = tmp[j];
    tmpc[j] = '\0';
    for (j = 0; j < (N - k - 5); j++) tmps[j] = tmp[j+k+5];
    tmps[j] = '\0';
  }
  if (N > 0) {
    IsMember = 1;
    if (IsTemplate) {
      strcpy(mclas, tmpc);
      strcpy(mstru, "<");
      strcat(mstru, tmps);
      strcat(mstru, ">");
    } else strcpy(mclas, tmp);
  } else strcpy(mclas, "\0");
  return(GOOD);
}  /*  LdmangleDiabGetClass function  */

/******************************************************************************
**   LdmangleDiabGetCode : get code name
******************************************************************************/
RETCODE LdmangleDiabGetCode(VOID){
  int j;
  int ReapeatNum;
  int ArgumentNum;
  int NestedNum;
  char tmp[2];

  ReapeatNum  = 0;
  ArgumentNum = 0;
  switch(MangStr[StrPtr]) {
    case 'A' : StrPtr++;
	       strcat(pa[ParPtr].d,"[");
	       while (isdigit(MangStr[StrPtr])) {
		 tmp[0] = MangStr[StrPtr];
		 tmp[1] = '\0';
		 strcat(pa[ParPtr].d, tmp);
		 StrPtr++;
	       }
	       strcat(pa[ParPtr].d, "]");
	       ParPtr--;
	       break;
    case 'N' : StrPtr++;
	       if (isdigit(MangStr[StrPtr])) {
		 ReapeatNum = MangStr[StrPtr] - 48;
		 StrPtr++;
		 while (isdigit(MangStr[StrPtr])) {
		   ArgumentNum = ArgumentNum * 10 + (MangStr[StrPtr] - 48);
		   StrPtr++;
		 }
		 StrPtr--;
	       } else SyxErr = 1;
	       if ((ArgumentNum > ParPtr) || (ArgumentNum == 0)) SyxErr = 1;
	       else {
		 for (j = 0; j < ReapeatNum; j++) {
		   strcpy(pa[ParPtr].a, pa[ArgumentNum - 1].a);
		   strcpy(pa[ParPtr].b, pa[ArgumentNum - 1].b);
		   strcpy(pa[ParPtr].c, pa[ArgumentNum - 1].c);
		   strcpy(pa[ParPtr].d, pa[ArgumentNum - 1].d);
		   strcpy(pa[ParPtr].e, pa[ArgumentNum - 1].e);
		   ParPtr++;
		 }
		 ParPtr--;
	       }
	       break;
    case 'Q' : NestedNum = 0;
	       StrPtr++;
	       if (isdigit(MangStr[StrPtr])) {
		 NestedNum = MangStr[StrPtr] - 48;
		 for (j = 0; j < NestedNum; j++) {
		   StrPtr++;
		   LdmangleDiabGetType(mtype);
		   strcpy(pa[ParPtr].a, mtype);
		 }
	       } else SyxErr = 1;
	       break;
    case 'M' : StrPtr++;
	       if (isdigit(MangStr[StrPtr])) {
		 strcpy(pa[ParPtr].e, "(");
		 LdmangleDiabGetType(mtype);
		 strcat(pa[ParPtr].e, mtype);
		 strcat(pa[ParPtr].e, "::*)");
		 ParPtr--;
	       } else SyxErr = 1;
	       break;
    case 'P' : strcpy(pa[ParPtr].b, "*");
	       ParPtr--;
	       break;
    case 'R' : strcpy(pa[ParPtr].b, "&");
	       ParPtr--;
	       break;
    case 'C' : strcpy(pa[ParPtr].c, "const ");
	       ParPtr--;
	       break;
    case 'S' : strcpy(pa[ParPtr].c, "signed ");
	       ParPtr--;
	       break;
    case 'U' : strcpy(pa[ParPtr].c, "unsigned ");
	       ParPtr--;
	       break;
    case 'V' : strcpy(pa[ParPtr].c, "volatile ");
	       ParPtr--;
	       break;
    case 'T' : StrPtr++;
	       while (isdigit(MangStr[StrPtr])) {
		 ArgumentNum = ArgumentNum * 10 + (MangStr[StrPtr] - 48);
		 StrPtr++;
	       }
	       StrPtr--;
	       strcpy(pa[ParPtr].a, pa[ArgumentNum - 1].a);
	       strcpy(pa[ParPtr].b, pa[ArgumentNum - 1].b);
	       strcpy(pa[ParPtr].c, pa[ArgumentNum - 1].c);
	       strcpy(pa[ParPtr].d, pa[ArgumentNum - 1].d);
	       strcpy(pa[ParPtr].e, pa[ArgumentNum - 1].e);
	       break;
    case 'i' : strcpy(pa[ParPtr].a, "int ");
	       break;
    case 'c' : strcpy(pa[ParPtr].a, "char ");
	       break;
    case 'd' : strcpy(pa[ParPtr].a, "double ");
	       break;
    case 'e' : strcpy(pa[ParPtr].a, "");
	       break;
    case 'f' : strcpy(pa[ParPtr].a, "float ");
	       break;
    case 'l' : strcpy(pa[ParPtr].a, "long ");
	       break;
    case 'm' : strcpy(pa[ParPtr].a, "long long ");
	       break;
    case 's' : strcpy(pa[ParPtr].a, "short ");
	       break;
    case 'r' : strcpy(pa[ParPtr].a, "long double ");
	       break;
    case 'v' : strcpy(pa[ParPtr].a, "void ");
	       break;
    default  : if (isdigit(MangStr[StrPtr])) {
		 LdmangleDiabGetType(mtype);
		 strcpy(pa[ParPtr].a, mtype);
		 strcat(pa[ParPtr].a, " ");
	       } else SyxErr = 1;
  }
  return(GOOD);
}  /*  LdmangleDiabGetCode function  */


/******************************************************************************
**   LdmangleDiabGetPara : get parameters
******************************************************************************/
RETCODE LdmangleDiabGetPara(VOID) {
  int j;
  char strtmp[20];

  ParPtr = 0;
  for (j = 0; j < 10; j++) {
    strcpy(pa[j].a, "\0");
    strcpy(pa[j].b, "\0");
    strcpy(pa[j].c, "\0");
    strcpy(pa[j].d, "\0");
    strcpy(pa[j].e, "\0");
  }
  //Hera 2/23/98
  strtmp[0] = '\0';
  if (MangStr[StrPtr] != 'F') {
     LdmangleDiabGetCode();
     ParPtr++;
     StrPtr++;
     strcpy(strtmp," ");
     strcat(strtmp,pa[0].c);
     strcpy(pa[0].c,"\0");
  }//Hera
  if (MangStr[StrPtr] == 'F') {
    StrPtr++;
    while (MangStr[StrPtr] != '\0') {
      LdmangleDiabGetCode();
      StrPtr++;
      ParPtr++;
    }
    strcat(mpara, "(");
    for (j = 0; j < ParPtr; j++) {
      if (j == 0) {
	strcat(mpara, pa[j].c);
	strcat(mpara, pa[j].a);
	strcat(mpara, pa[j].d);
	strcat(mpara, pa[j].b);
	strcat(mpara, pa[j].e);
      } else {
	strcat(mpara, ", ");
	strcat(mpara, pa[j].c);
	strcat(mpara, pa[j].a);
	strcat(mpara, pa[j].d);
	strcat(mpara, pa[j].b);
	strcat(mpara, pa[j].e);
      }
    }
    strcat(mpara, ")");
  }/*else {
    ParPtr = 0;
    while ((MangStr[StrPtr]) != '\0') {
      if (MangStr[StrPtr] == 'F') SyxErr = 1;
      LdmangleDiabGetCode();
      StrPtr++;
      ParPtr++;
    }
    if (ParPtr > 1) SyxErr = 1;
    else {
      strcpy(margu, pa[0].c);
      strcat(margu, pa[0].a);
      strcat(margu, pa[0].d);
      strcat(margu, pa[0].b);
      strcat(margu, pa[0].e);
    }
  }  --Hera 2/23/98*/
  //Hera 2/23/98
  if (strtmp[0] != '\0')
     strcat(mpara,strtmp);
  //Hera
  return(GOOD);
}  /*  LdmangleDiabGetPara function  */


/******************************************************************************
**   LdmangleDiabConcat : concat demangled string
******************************************************************************/
RETCODE LdmangleDiabConcat(VOID) {
  strcpy(FuncStr, margu);
  strcat(FuncStr, mclas);
  strcat(FuncStr, mstru);
  if (IsMember) strcat(FuncStr, "::");
  strcat(FuncStr, mfunc);
  strcat(FuncStr, mpref);
  if (IsClass)  strcat(FuncStr, mclas);
  strcat(FuncStr, mpara);
  return(GOOD);
}  /*  LdmangleDiabConcat function  */


/******************************************************************************
**   LdmangleDiabDemangle : translate mangling string to programming string
******************************************************************************/
RETCODE LdmangleDiabDemangle(LPSTR instr, LPSTR *outstr) {
  IsClass    = 0;
  IsMember   = 0;
  StrPtr     = 0;
  SyxErr     = 0;

  FuncStr = (CHAR *) TMalloc(128);
  MangStr = (CHAR *) TMalloc(128);
  mfunc = (CHAR *) TMalloc(80);
  mclas = (CHAR *) TMalloc(80);
  mstru = (CHAR *) TMalloc(80);
  mtype = (CHAR *) TMalloc(80);
  mpref = (CHAR *) TMalloc(80);
  margu = (CHAR *) TMalloc(80);
  mpara = (CHAR *) TMalloc(200);
  tmpc  = (CHAR *) TMalloc(80);
  strcpy(margu, "\0");
  strcpy(mclas, "\0");
  strcpy(mstru, "\0");
  strcpy(mpref, "\0");
  strcpy(mfunc, "\0");
  strcpy(mtype, "\0");
  strcpy(mpara, "\0");
  strcpy(tmpc,  "\0");
  strcpy(MangStr, instr);
  if (!strncmpi(MangStr, "__op", 4)) {
    ParPtr = 0;
    StrPtr = 4;
    while (MangStr[StrPtr] != '_') {
      if (MangStr[StrPtr] == '\0') {
	SyxErr = 1;
	break;
      } else {
	LdmangleDiabGetCode();
	StrPtr++;
	ParPtr++;
      }
    }
    if (ParPtr == 1) {
      strcpy(mpref, "operator ");
      strcat(mpref, pa[0].c);
      strcat(mpref, pa[0].a);
      strcat(mpref, pa[0].d);
      strcat(mpref, pa[0].b);
      strcat(mpref, pa[0].e);
    }
    StrPtr++;
    if (MangStr[StrPtr] != '_') SyxErr = 1;
    StrPtr++;
    LdmangleDiabGetClass();
    LdmangleDiabGetPara();
  } else if (!strncmpi(MangStr, "__", 2)) {
    LdmangleDiabGetPrefix();
    LdmangleDiabGetClass();
    LdmangleDiabGetPara();
  } else {
    LdmangleDiabGetFunc();
    LdmangleDiabGetClass();
    LdmangleDiabGetPara();
  }
  LdmangleDiabConcat();
/*  if (SyxErr) strcpy(*outstr, (LPSTR)MangStr);
  else        strcpy(*outstr, (LPSTR)FuncStr); */
  if (SyxErr)
     memcpy((LPSTR *)outstr,(LPSTR)MangStr,strlen(MangStr)+1);
  else
     memcpy((LPSTR *)outstr,(LPSTR)FuncStr,strlen(FuncStr)+1);
  TFree(FuncStr);
  TFree(MangStr);
  TFree(mfunc);
  TFree(mclas);
  TFree(mstru);
  TFree(mtype);
  TFree(mpref);
  TFree(margu);
  TFree(mpara);
  TFree(tmpc);
  if (SyxErr) return(FALSE);
  else        return(GOOD);
}   /*  Demangle function  */

/******************************************************************************
**   LdmangleDiabGetValue : get the value and size of the mangling string
******************************************************************************/
RETCODE LdmangleDiabGetValue(HANDLE hfile, LPSTR instr, U32* ST_value, U32* ST_size) {
  //CHAR *Name;
  CHAR name[ELF_IDNLEN];
  CHAR *mstr;
  int  StrNum,i;    // count the number of strings
  U32  init;
  U32  index;

  mstr = (CHAR *) TMalloc(100);
  strcpy(mstr, "_");   // add a '_' char to the string for mangling functions
  strcat(mstr, instr);
  _llseek(hfile, strtab_offset, SEEK_SET);
  index = init = 0;
  StrNum = i = 0;
  while(index < strtab_size && !init) {
     if((name[i] = GetELFByte(hfile)) != '\0'){
        index++;
        i++;
     }
     else{
        StrNum++;
        if(!strcmp(name,mstr) && !init) 
           init = StrNum;
        index++;
        i = 0;
     }
  }      
  if (init > 0) {
    _llseek(hfile, (symtab_offset + (StrNum * 16) + 4), SEEK_SET);
    *ST_value  = GetELFU32(hfile);
    *ST_size   = GetELFU32(hfile);
  }
  TFree(mstr);
  return(GOOD);
}

/************************************* EOF ********************************/
