/****************************************************************************
**
**  Name:  varutil.c
**
**  Description:
**     Misc and general routines of variable server.
**
**  Status:  PRELIMINARY 
**
**  $Log:   S:/tbird/mt2_186/varsrv/varutil.c_v  $
** 
**    Rev 1.0   16 Dec 1996 14:48:04   Judy
** Initial revision.
** 
**    Rev 1.33   02 May 1995 13:58:52   marilyn
** Fixes ppr 10245, CheckForTypedef is more bulletproof in case of
** tool error.
** 
**    Rev 1.32   28 Mar 1995 11:43:28   marilyn
** Updated IsPointer interface and also MakeCompositeVarName routine.
** 
**    Rev 1.31   03 Feb 1995 10:56:40   marilyn
** Fixed ppr 9961 where incorrect information was shown for child vars
** of dereferenced pointers.  Changes to UpdateChildVars.
** 
**    Rev 1.30   01 Feb 1995 14:28:44   marilyn
** Support new field invalidAddress when updating child vars.  ppr 9961.
** 
**    Rev 1.29   24 Oct 1994 11:49:12   marilyn
** Fixed bug in GetPtrDereference where the parent address (start address)
** was modified before duping.  Also made changes to UpdateChildVars to
** fix ppr 9964.
** 
**    Rev 1.28   08 Sep 1994 16:46:02   marilyn
** Fixed numerous problems related to X86 display, editing and dereferencing
** pointers.  Added special support for X86 function pointers.
** 
**    Rev 1.27   24 Aug 1994 09:55:42   marilyn
** Updated for X86 support.
** 
**    Rev 1.26   16 Jun 1994 13:50:08   nghia
** Merged 1.25.1.2 to trunk.
** 
**    Rev 1.25.1.2   31 May 1994 17:38:52   nghia
** Revised GetPtrDereference() to use the Address Server AdrConvertPointer
** to handle dereferencing.  This applies to both global and local pointer
** variables.  
** Support HC16 Var index register.
** 
**    Rev 1.25.1.1   31 May 1994 12:00:38   nghia
** Fixed GPF 9401 - Uninitialized local pointers in MapArrayLine2Offset() 
** sometimes can cause the system to get a GPF.   Initialized pointers = NULL.
** 
**    Rev 1.25.1.0   27 May 1994 11:47:16   nghia
** Fixed GPF bugs for PV 2.2b:
** - PPR 9401 - inspect elements of a 5 dimension array get GPF.
** 
**    Rev 1.25   22 Apr 1994 15:24:26   marilyn
** Modified UpdateChildVars to use pointer type of parent pointer to 
** calculate the pointer size.
** 
**    Rev 1.24   28 Feb 1994 17:06:20   marilyn
** Moved maxOutput routines to the address server. Updated interfaces.
** 
**    Rev 1.23   18 Nov 1993 17:31:00   nghia
** Fixed PPR 9191 - Dereference of SMALL pointer variable.
** Use ptrSize for byte flipping.
** 
**    Rev 1.22   01 Nov 1993 10:17:28   nghia
** Fixed PPR 8962 - Variable Server handles SMALL/LARGE pointer types
** Revised CheckTypeDef() to handle SMALL/LARGE pointer differently.
** 
**    Rev 1.21   15 Jun 1993 11:48:16   mindy
** Change CHECKENDIAN_... to use FlipBuffer routines.
** 
**    Rev 1.20   29 Mar 1993 11:33:52   nghia
** Fixed bug: Processing typedef for array element.  To complete the process
** of mapping line to offset.  The VarServser needs to check for user-defined
** type for array too.
** 
**    Rev 1.20   29 Mar 1993 11:32:24   nghia
** Fixed bug: Check for user-defined type for array.
** 
**    Rev 1.19   15 Jan 1993 08:28:48   marilyn
** Had to remove changes to UpdateChildVars which were preventing normal
** ptrs from dereferencing more than once.  Now pts within unions
** will not dereference, but this is a less serious bug to ship. 
** 
**    Rev 1.18   12 Jan 1993 17:05:42   marilyn
** Fine tuning to UPdateChildVars.
** 
**    Rev 1.17   11 Jan 1993 15:56:18   marilyn
** Changes to updateChildVars.
** 
**    Rev 1.16   04 Dec 1992 09:54:38   marilyn
** Enum require a line count of 1 but the member count is a count of defined
** enums.  Now use 1 for enum member counts.
** 
**    Rev 1.15   02 Dec 1992 13:52:58   marilyn
** Updated CheckWarnings and made changes to UpdateChildVars to handle
** edits to unions correctly.
** 
**    Rev 1.14   11 Nov 1992 11:58:40   marilyn
** Fixed bug with very large array indices.
** 
**    Rev 1.14   11 Nov 1992 11:54:48   marilyn
** Fixed array indices not to be negative.
** 
**    Rev 1.13   04 Nov 1992 17:44:54   marilyn
** Fixed pprs 7170,7184,7204,7344,7345.
** 
**    Rev 1.12   22 Oct 1992 21:28:00   marilyn
** Fixed naming problem of dereferenced ptrs.
** 
**    Rev 1.11   21 Oct 1992 16:15:00   marilyn
** Fixed some bugs in addressing modes.
** 
**    Rev 1.10   15 Oct 1992 17:54:54   marilyn
** Fixed several bugs for beta.
** 
**    Rev 1.9   10 Sep 1992 15:21:22   marilyn
** Needed to check the endian after stack reads.
** 
**    Rev 1.8   04 Aug 1992 16:52:36   marilyn
** Added UpdateChildVars.
** 
**    Rev 1.7   31 Jul 1992 16:50:18   marilyn
** Modified Maparrayline2offset to fix bugs with multi-dim arrays and
** also to return the indices.
** 
**    Rev 1.6   28 May 1992 16:36:04   marilyn
** Modified interface for StkRead and StkWrite.
** 
**    Rev 1.5   03 Jan 1980 16:27:40   marilyn
** Fixed bug in ComponentAddress where the storage type was changed to
** static. Now it is set to global.
** 
**    Rev 1.4   13 May 1992 11:23:06   marilyn
** Added GetSubArrayType for array indexing.
** 
**    Rev 1.3   24 Apr 1992 16:49:48   marilyn
** Added CheckForTypedef routine.
** 
**    Rev 1.2   17 Apr 1992 16:19:38   marilyn
** Added GetComponentAddress and GetPtrDereference routines.
** 
**    Rev 1.1   06 Apr 1992 11:17:54   marilyn
** Moved CheckWarning from varservr.c
** 
**    Rev 1.0   03 Apr 1992 08:55:58   marilyn
** Initial revision.
**
**  $Header:   S:/tbird/mt2_186/varsrv/varutil.c_v   1.0   16 Dec 1996 14:48:04   Judy  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#ifndef _BASEWIND_
#include "basewind.h"
#endif

#ifndef _VARSERVR_
#include "varservr.h"
#endif

#ifndef _VARUTIL_
#include "varutil.h"
#endif

#ifndef _VARERRS_
#include "varerrs.h"
#endif

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

#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif

#ifndef _VARENDIA_
#include "varendia.h"
#endif

#ifndef __STRING_H
#include <string.h>
#endif

#ifndef __STDLIB_H
#include <stdlib.h>
#endif

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/

                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/

extern VS_VAR_TABLE_TYPE varTable;
extern U32 currVarTableSize;
extern PROCESSOR_FAMILY procFamily;

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/

RETCODE PRIVATE X86UpdateFuncPtrAddress(DESCRIPTOR address,
                                        TYPE_SUBHEADER_TYPE *typeInfo);

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/


/***********************************************************************
**
**  CheckForTypedef :
**
************************************************************************/
VOID CheckForTypedef(TYPE_SUBHEADER_TYPE *varTypeInfo,
                     TYPE_SUBHEADER_TYPE **typedefTypeInfo,
                     TYPE_SUBHEADER_TYPE **baseTypeTypeInfo) {

   *baseTypeTypeInfo = NULL;
   *typedefTypeInfo = NULL;
   if (varTypeInfo != NULL) {
      if (varTypeInfo->th.typeChoice == SIMPLE_TYPE_CLASS) {
         *baseTypeTypeInfo = varTypeInfo;
         *typedefTypeInfo = NULL;
      }
      else {
         switch (varTypeInfo->th.t.complexType) {
            case TY_TYPE:
               /*
               **  we found a typedef!
               **  make sure the subsequent type is not another typedef
               */
               *typedefTypeInfo = varTypeInfo;
               *baseTypeTypeInfo = varTypeInfo->next;
               while (*baseTypeTypeInfo != NULL) {
                  if (((*baseTypeTypeInfo)->th.typeChoice == COMPLEX_TYPE_CLASS)
                      && ((*baseTypeTypeInfo)->th.t.complexType == TY_TYPE))
                        *baseTypeTypeInfo = (*baseTypeTypeInfo)->next;
                  else
                     break;
               }
               break;
            default:
               *baseTypeTypeInfo = varTypeInfo;
               *typedefTypeInfo = NULL;
               break;
         }
      }
   }
}

/************************************************************************
**
**   CheckWarning :
**
*************************************************************************/
RETCODE CheckWarning(RETCODE retcode,
                     RETCODE *errcode) {

   if (retcode == GOOD) {
      *errcode = retcode;
      return GOOD;
   }
   else
      switch (retcode & E_COMPONENT_MASK) {
         case MODULE_SYMBOLS :
            *errcode = VS_WARNING_SYMBOL;
            break;
         case MODULE_ADDRESS :
            *errcode = VS_WARNING_ADDRESS;
            break;
         case MODULE_STACK :
            *errcode = VS_WARNING_STACK;
            break;
         case MODULE_VAR :
            *errcode = VS_WARNING_VARIABLE;
            break;
         case MODULE_SYSTEM :
         case MODULE_GENERIC :
            *errcode = VS_WARNING_SYSTEM;
            break;
         case MODULE_MEMORY:
            *errcode = VS_WARNING_MEMORY;
            break;
         case MODULE_CPU:
            *errcode = VS_WARNING_CPU;
            break;
         default :
            *errcode = retcode;
            return retcode;
      };
   return GOOD;
}

/*************************************************************************
**
**  GetComponentAddress
**
** compute the address of the component using the component
** offset and the root variable's address.    If the root type
** is a pointer then use the pointers value as the address.
**
**
***************************************************************************/
RETCODE GetComponentAddress(VS_VAR_ENTRY_TYPE *rootVar,
                            TYPE_INDEX *typeIndex,
                            U32 byteOffset,
                            GET_VAR_ADDR_STRUCT *addr,
                            VAR_STORAGE_CLASS *storageClass,
                            BOOLEAN *dereferencedPtr) {

   TYPE_SUBHEADER_TYPE *subTypeInfo;
   TYPE_SUBHEADER_TYPE typeHeader;
   U8 typeNameString[VS_MAX_STRING];
   RETCODE error;

   memset(&typeHeader,'\0',sizeof(typeHeader));
   typeHeader.th.typeName = (LPSTR)typeNameString;
   if ((error = SymGetTypeHeader(*typeIndex,
         (TYPE_HEADER_TYPE *)&typeHeader)) != GOOD)
      return error;
   typeHeader.typeIndex = *typeIndex;
   if (typeHeader.th.typeChoice == COMPLEX_TYPE_CLASS) {
      while (typeHeader.th.t.complexType == TY_TYPE) {
         if ((error = SymGetTypeTypeIndex(*typeIndex,typeIndex)) != GOOD)
            return error;
         if ((error = SymGetTypeHeader(*typeIndex,
               (TYPE_HEADER_TYPE *)&typeHeader)) != GOOD)
            return error;
         typeHeader.typeIndex = *typeIndex;
      }
      if (IsPointer(&typeHeader.th)) {
         /*
         ** in other words its a pointer or a typedef of a ptr
         */
         if ((error = GetPtrDereference(rootVar->registerClass,
               rootVar->storageClass,
               &typeHeader, typeHeader.th.t.complexType,
               byteOffset, rootVar->frameNum,rootVar->frameType,
               &rootVar->address, addr)) != GOOD)
            return error;
         *storageClass = GLOBAL_VAR_CLASS;
         if ((error = GetBaseTypeForPointer(&typeHeader))
               != GOOD)
            return error;
         /*
         ** GetSubComponentType(&typeHeader,&subTypeInfo);
         */
         if (typeHeader.next != NULL)
            subTypeInfo = typeHeader.next;
         *typeIndex = subTypeInfo->typeIndex;
         *dereferencedPtr = TRUE;
         if ((error = FreeSubTypes(&typeHeader)) != GOOD)
            return error;
      }
      else {
        *dereferencedPtr = FALSE;
         if ((error = GetAddress(rootVar->registerClass,
               rootVar->storageClass,byteOffset,&rootVar->address,
               addr)) != GOOD)
            return error;
      }
   }
   if (typeHeader.th.typeChoice == SIMPLE_TYPE_CLASS) {
      *dereferencedPtr = FALSE;
      if ((error = GetAddress(rootVar->registerClass,rootVar->storageClass,
            byteOffset,&rootVar->address,addr)) != GOOD)
         return error;
   }

   return GOOD;
}

/************************************************************************
**
**  GetPtrDereference
**
** Expandable pointers can be auto, static, or register class.
** You must calculate the address of where the pointer points to
** based on storage and register class.
**
************************************************************************/
RETCODE GetPtrDereference(VAR_REGISTER_CLASS registerClass,
                          VAR_STORAGE_CLASS storageClass,
                          TYPE_SUBHEADER_TYPE *typeInfo,
                          COMPLEX_TYPE ptrType,
                          U32 byteOffset,
                          U8 frameNum,
                          U8 frameType,
                          GET_VAR_ADDR_STRUCT *startAddr,
                          GET_VAR_ADDR_STRUCT *newAddr) {

   S32 signedByteOffset;
   U32 regValue;
   RETCODE error;

   if (registerClass == NOT_REG) {
      if (storageClass != AUTO_VAR_CLASS) {
         /*
         **  static based
         */
         if ((error = AdrDuplicateAddress(startAddr->getFixedAddrDesc,
               &newAddr->getFixedAddrDesc)) != GOOD)
            return error;
         if ((error = AdrAddToAddress(newAddr->getFixedAddrDesc,
               byteOffset)) != GOOD)
            return error;
         if ((error = AdrConvertPointerToAddress(newAddr->getFixedAddrDesc,
               typeInfo->th.sizeInMAUs, ptrType)) != GOOD)
            return error;
      }
      else {
         /*
         ** auto based - Remember stack reads allocate the buffer.
         */
         signedByteOffset = (S32)byteOffset;
         if (startAddr->addrData.getAutoVar.autoVarOffset > 0)
             signedByteOffset = -(signedByteOffset);
         if ((error = StkCalcStkOffset(&startAddr->addrData.getAutoVar.
               autoVarOffset,signedByteOffset)) != GOOD)
            return error;
         movmem(startAddr,newAddr,sizeof(*startAddr));
         /* Get stack address base on the variable stack offset */
         if ((error = StkGetStackAddress(
               newAddr->addrData.getAutoVar.autoVarOffset,
               frameNum,frameType, &newAddr->getFixedAddrDesc)) != GOOD)
            return error;
         // save the stack address of the local variable.
         if ((error = AdrCopyAddress(newAddr->getFixedAddrDesc,
               startAddr->getFixedAddrDesc)) != GOOD)
            return error;
         if ((error = AdrConvertPointerToAddress(newAddr->getFixedAddrDesc,
               typeInfo->th.sizeInMAUs, ptrType)) != GOOD)            
            return error;
      }
   }
   else {  /* pointer in a register */
      if (registerClass == LIVING_REG) {
         if ((error = CpuGetRegister(startAddr->addrData.getRegisterIndex.
               varLivingReg,&regValue)) != GOOD)
            return error;
      }
      else {
         if ((error = CpuGetRegister(startAddr->addrData.getLockedReg.
               getRegIndex.regIndex,&regValue)) != GOOD)
            return error;
      }
      movmem(startAddr,newAddr, sizeof(*startAddr));
      if ((error = AdrCreateAddress(&newAddr->getFixedAddrDesc)) != GOOD)
         return error;
      if ((error = AdrSetAddrOffset(newAddr->getFixedAddrDesc,
            regValue)) != GOOD)
         return error;
      
   }
   return( X86UpdateFuncPtrAddress(newAddr->getFixedAddrDesc,typeInfo));
}

/************************************************************************
**
**  GetAddress
**
** You must calculate the address of the variable
** based on storage and register class.
**
************************************************************************/
RETCODE GetAddress(VAR_REGISTER_CLASS registerClass,
                          VAR_STORAGE_CLASS storageClass,
                          U32 byteOffset,
                          GET_VAR_ADDR_STRUCT *startAddr,
                          GET_VAR_ADDR_STRUCT *newAddr) {

   S32 signedByteOffset;
   U32 regValue;
   RETCODE error;

   if (registerClass == NOT_REG) {
      if (storageClass != AUTO_VAR_CLASS) {
         /*
         **  static based
         */
         if ((error = AdrDuplicateAddress(startAddr->getFixedAddrDesc,
               &newAddr->getFixedAddrDesc)) != GOOD)
            return error;
         if ((error = AdrAddToAddress(newAddr->getFixedAddrDesc,
               byteOffset)) != GOOD)
            return error;
      }
      else {
         /*
         ** auto based - Remember stack reads allocate the buffer.
         */
         movmem(startAddr,newAddr,sizeof(*startAddr));
         newAddr->getFixedAddrDesc = NULL;
         signedByteOffset = (S32)byteOffset;
         if (newAddr->addrData.getAutoVar.autoVarOffset > 0)
             signedByteOffset = -(signedByteOffset);
         if ((error = StkCalcStkOffset(&newAddr->addrData.getAutoVar.
               autoVarOffset,signedByteOffset)) != GOOD)
            return error;
      }
   }
   else {  /* var in a register */
      if (registerClass == LIVING_REG) {
         if ((error = CpuGetRegister(startAddr->addrData.getRegisterIndex.
               varLivingReg,&regValue)) != GOOD)
            return error;
      }
      else {
         if ((error = CpuGetRegister(startAddr->addrData.getLockedReg.
               getRegIndex.regIndex,&regValue)) != GOOD)
            return error;
      }
      movmem(startAddr,newAddr,sizeof(*startAddr));
      if ((error = AdrCreateAddress(&newAddr->getFixedAddrDesc)) != GOOD)
         return error;
      if ((error = AdrSetAddrOffset(newAddr->getFixedAddrDesc,
            regValue)) != GOOD)
         return error;
   }
   return GOOD;
}


/*************************************************************************
**
**  GetSubArrayType :
**
************************************************************************/
VOID GetSubArrayType(TYPE_SUBHEADER_TYPE *typeInfo,
                     TYPE_SUBHEADER_TYPE **baseTypeInfo) {


   *baseTypeInfo = typeInfo;
   while ((*baseTypeInfo)->next != NULL) {
      *baseTypeInfo = (*baseTypeInfo)->next;
      if ((*baseTypeInfo)->th.typeChoice == SIMPLE_TYPE_CLASS)
         return;
      if (((*baseTypeInfo)->th.typeChoice == COMPLEX_TYPE_CLASS) &&
            ((*baseTypeInfo)->th.t.complexType != TY_C_ARRAY))
         return;
   }
   return;

}
/*************************************************************************
**
**  FindSubArrayType :
**
************************************************************************/
VOID FindSubArrayType(TYPE_SUBHEADER_TYPE *typeInfo,
                      ARRAY_INDEX_NODE *arrayIndices,
                      TYPE_SUBHEADER_TYPE **baseTypeInfo) {

   ARRAY_INDEX_NODE *indices;

   indices = arrayIndices;
   *baseTypeInfo = typeInfo;
   while (indices != NULL)  {
      indices = indices->next;
      *baseTypeInfo = (*baseTypeInfo)->next;
   }
   return;

}
/*************************************************************************
**
**  GetSubComponentType :
**
************************************************************************/
VOID GetSubComponentType(TYPE_SUBHEADER_TYPE *typeInfo,
                         TYPE_SUBHEADER_TYPE **baseTypeInfo) {

   *baseTypeInfo = typeInfo;
   while ( (*baseTypeInfo)->next != NULL)
      *baseTypeInfo = (*baseTypeInfo)->next;
   return;

}


/*************************************************************************
**
**  MakeCompositeVarName :
**
**************************************************************************/
VOID  MakeCompositeVarName(LPSTR rootVarName,
                           TYPE_SUBHEADER_TYPE *rootTypeInfo,
                           BOOLEAN rootdereferencedPtr,
                           LPSTR compName,
                           ARRAY_INDEX_NODE *arrayIndices,
                           LPSTR varName)  {
   ARRAY_INDEX_NODE *ptr;
   COMPLEX_TYPE rootVarType;
   TYPE_SUBHEADER_TYPE *baseTypeInfo=NULL;
   TYPE_SUBHEADER_TYPE *typeTypeInfo=NULL;
   U8 string[20];

   CheckForTypedef(rootTypeInfo,&typeTypeInfo,&baseTypeInfo);
   if (baseTypeInfo->th.typeChoice == COMPLEX_TYPE_CLASS)
      rootVarType = baseTypeInfo->th.t.complexType;
   else
      rootVarType = baseTypeInfo->th.t.simpleType;  
   if (*compName == '\0') {
      if (IsPointer(&baseTypeInfo->th)) {
         strcat(varName,"*");
      }
      else {
         if (rootVarType == TY_C_ARRAY) {
            /* we could be expanding a component of an array of ptrs
            ** check for the ptr type.
            */
            FindSubArrayType(rootTypeInfo,arrayIndices,&baseTypeInfo);
            if ((baseTypeInfo->th.typeChoice == COMPLEX_TYPE_CLASS) &&
                  IsPointer(&baseTypeInfo->th)) {
               strcat(varName,"*");
            }
         }
      }
   }
   /* If the root type is a deferenced ptr and we are dereferencing
   ** another ptr in a struct, then use the ptr convention -> and drop
   ** the contentsOf convention.
   */
   if ((*compName != '\0') && (rootdereferencedPtr)) {
      if (*rootVarName == '*')
         strcat(varName,++rootVarName);
      else {   // find the contentsOf convention "*X" 
               // we will replace it with "X->"
         LPSTR foundChar;
         foundChar = _fstrrchr(rootVarName,'*');
         if (foundChar != NULL) {
            _fstrncpy(varName,rootVarName,(foundChar-rootVarName));
            strcat(varName,++foundChar);
         }
         else
            strcat(varName,rootVarName);
      }
   }
   else
      strcat(varName,rootVarName);
   if (*compName != '\0') {
      if (rootdereferencedPtr)
         strcat(varName,"->");
      else {
         switch (rootVarType)  {
            case TY_STRUCT :
            case TY_UNION :
               strcat(varName,".");
               break;
            case TY_SMALL_PTR :
            case TY_LARGE_PTR :
            case TY_16_16_PTR :
            case TY_16_32_PTR :
               strcat(varName,"->");
               break;
            case TY_C_ARRAY :
               while (arrayIndices != NULL) {
                  strcat(varName,"[");
                  ultoa(arrayIndices->index,(LPSTR)string,10);
                  strcat(varName,(LPSTR)string);
                  strcat(varName,"]");
                  ptr = arrayIndices;
                  arrayIndices = arrayIndices->next;
                  TFree((VOID *)ptr);
               }
               strcat(varName,".");
               break;
            default :
               strcat(varName,".");
               break;
         }
      }
      strcat(varName,compName);
   }
   else {
      if (rootVarType == TY_C_ARRAY)  {
         while (arrayIndices != NULL) {
            strcat(varName,"[");
            ultoa(arrayIndices->index,(LPSTR)string,10);
            strcat(varName,(LPSTR)string);
            strcat(varName,"]");
            ptr = arrayIndices;
            arrayIndices = arrayIndices->next;
            TFree((VOID *)ptr);
         }
      }
   }
   return;
}



/************************************************************************
**
**   MapArrayLine2Offset :
**
************************************************************************/
RETCODE MapArrayLine2Offset(TYPE_SUBHEADER_TYPE *typeInfo,
                            U16 lineNum,
                            U16 priorHeaderCount,
                            U32 *offset,
                            U16 *memberIndex,
                            TYPE_INDEX *typeIndex,
                            ARRAY_LIST_NODE **arrayNode,
                            ARRAY_INDEX_NODE **arrayIndexNode) {

   TYPE_Z_STRUCT cArray;
   U16 memberCount;
   U16 lastArrayLineCount;
   U32 thisLine,numBlocks;
   U16 lineCount;
   S32 lineDif;
   ARRAY_LIST_NODE *nodePtr = NULL, *tempNode = NULL,*lastNode = NULL;
   ARRAY_INDEX_NODE *indexNode = NULL, *indexNodePtr = NULL;
   SUB_TYPE_LIST_NODE *subNode = NULL, *subNodePtr = NULL;
   TYPE_SUBHEADER_TYPE *subType = NULL;
   LOOP_VAR i;
   RETCODE error;

   if ((typeInfo->th.typeChoice == SIMPLE_TYPE_CLASS) ||
       (typeInfo->next == NULL)  ||
       ((typeInfo->th.typeChoice == COMPLEX_TYPE_CLASS) &&
        (typeInfo->th.t.complexType != TY_C_ARRAY))) {
      if ((nodePtr = (ARRAY_LIST_NODE *)TMalloc(sizeof(ARRAY_LIST_NODE)))
            == NULL)
         return ER_OUT_OF_MEMORY;
      nodePtr->next = NULL;
      nodePtr->previous = NULL;
      nodePtr->subNode = NULL;
      *arrayNode = nodePtr;
      if ((error = SymGetTypeMemberCount(typeInfo->typeIndex,&memberCount))
            != GOOD)
         return error;
      if (typeInfo->th.typeChoice == SIMPLE_TYPE_CLASS) {
         *offset = 0;
         nodePtr->size = typeInfo->th.sizeInMAUs;
         nodePtr->numLines = memberCount;
         return GOOD;
      }
      switch (typeInfo->th.t.complexType) {
         case TY_STRUCT :
         case TY_UNION :  {
            TYPE_S_U_STRUCT compInfo;
            U8 nameString[VS_MAX_STRING];

            compInfo.name = (LPSTR)nameString;
            *offset = 0;
            nodePtr->size = typeInfo->th.sizeInMAUs;
            nodePtr->numLines = memberCount + HEADER_AND_FOOTER;
            for (i=0; i < memberCount; i++) {
               if ((error = SymGetTypeStructUnionNth(typeInfo->typeIndex,
                     i,&compInfo)) != GOOD)
                  return error;
               if ((subNode = (SUB_TYPE_LIST_NODE *)TMalloc(sizeof
                     (SUB_TYPE_LIST_NODE))) == NULL)
                  return ER_OUT_OF_MEMORY;
               subNode->next = NULL;
               subNode->offset = compInfo.offset;
               subNode->numLines = 1;
               if (nodePtr->subNode == NULL) {
                  nodePtr->subNode = subNode;
               }
               else {
                  subNodePtr = nodePtr->subNode;
                  while (subNodePtr->next != NULL)
                     subNodePtr = subNodePtr->next;
                  subNodePtr->next = subNode;
               }
            }
            return GOOD;
         }
         case TY_SMALL_PTR :
         case TY_LARGE_PTR :
         case TY_16_16_PTR :
         case TY_16_32_PTR :
            *offset = 0;
            nodePtr->size = typeInfo->th.sizeInMAUs;
            nodePtr->numLines = memberCount;
            return GOOD;
         case TY_ENUM_C :
            *offset = 0;
            nodePtr->size = typeInfo->th.sizeInMAUs;
            /*
            **  on enums the member count is the number of enumerated
            **  types in the enum and does not correspond to the number
            **  of lines or fields required by the formatted enum,
            **  therefore we indicate the lines required by 1.
            */
            nodePtr->numLines = 1;
            return GOOD;
         default :
            *offset = 0;
            nodePtr->size = typeInfo->th.sizeInMAUs;
            nodePtr->numLines = memberCount;
            return GOOD;
      }
   }
   /* Process Array of type */
   if ((error = SymGetTypeCArray(typeInfo->typeIndex,&cArray)) != GOOD)
      return error;
   /* Check for array of typedef.
   ** 09/06/94 Marilyn
   ** Use temporary subtype so that the original typeInfo size is
   ** preserved.  if array -> typedef -> builtin type then resetting
   ** typeInfo to typeInfo->next (the typedef) looses the original typeInfo
   ** information of the array because when unwinding from recursion the
   ** typedef info is in typeInfo instead of array info.
   */
   subType = typeInfo->next;
   while (subType->th.t.complexType == TY_TYPE) {
      subType = subType->next;
   }
   if ((error = MapArrayLine2Offset(subType,lineNum,
         priorHeaderCount+1,offset,memberIndex,typeIndex,arrayNode,
         arrayIndexNode)) != GOOD)
      return error;
   if (*arrayNode == NULL)
      return GOOD;
   lastArrayLineCount = (*arrayNode)->numLines;
   lineCount = HEADER_AND_FOOTER + ((cArray.highBound + 1)
         * lastArrayLineCount) + priorHeaderCount;

   if (lineNum >= lineCount) {
      if ((nodePtr = (ARRAY_LIST_NODE *)TMalloc(sizeof(ARRAY_LIST_NODE)))
            == NULL)
         return ER_OUT_OF_MEMORY;
      nodePtr->next = NULL;
      nodePtr->previous = *arrayNode;
      nodePtr->subNode = NULL;
      (*arrayNode)->next = nodePtr;
      *arrayNode = nodePtr;
      nodePtr->size = typeInfo->th.sizeInMAUs;
      nodePtr->numLines = lineCount - priorHeaderCount;
   }

   if ((lineNum < lineCount) && (*offset == 0)) {
      /*
      ** calculate offset to get as close to the previously
      ** nested level of arrays as possible.  Follow the
      ** nesting pattern until the line is found.
      */
      lastNode = NULL;
      nodePtr = *arrayNode;
      thisLine = priorHeaderCount + 1;
      if (arrayIndexNode != NULL) {
         *arrayIndexNode = NULL;
         if (priorHeaderCount) {
            for (i = 0; i < priorHeaderCount; i++) {
               if ((indexNode = (ARRAY_INDEX_NODE *)TMalloc(sizeof(
                     ARRAY_INDEX_NODE))) == NULL)
                  return ER_OUT_OF_MEMORY;
               indexNode->next = NULL;
               indexNode->index = 0;
               if (*arrayIndexNode == NULL) {
                  *arrayIndexNode = indexNode;
               }
               else {
                  indexNodePtr = *arrayIndexNode;
                  while (indexNodePtr->next != NULL)
                     indexNodePtr = indexNodePtr->next;
                  indexNodePtr->next = indexNode;
               }
            }
         }
      }
      while (nodePtr != NULL) {
         indexNode = NULL;
         lineDif = (S32)(lineNum) - (S32)(thisLine);
         if (arrayIndexNode != NULL) {
            if ((*arrayIndexNode == NULL) || (lineNum == thisLine) ||
                  (lineDif > 0)) {
               if ((lineDif >= 0) && (lastNode != nodePtr)) {
                  if ((indexNode = (ARRAY_INDEX_NODE *)TMalloc(sizeof(
                        ARRAY_INDEX_NODE))) == NULL)
                     return ER_OUT_OF_MEMORY;
                  indexNode->next = NULL;
                  indexNode->index = 0;
                  if (*arrayIndexNode == NULL) {
                     *arrayIndexNode = indexNode;
                  }
                  else {
                     indexNodePtr = *arrayIndexNode;
                     while (indexNodePtr->next != NULL)
                        indexNodePtr = indexNodePtr->next;
                     indexNodePtr->next = indexNode;
                  }
               }
            }
         }
         lastNode = nodePtr;
         if (lineNum > thisLine) {
            numBlocks = (lineNum - thisLine)/nodePtr->numLines;
            if (indexNode != NULL)
               indexNode->index = numBlocks;
            if (numBlocks != 0) {
               *offset += (numBlocks * nodePtr->size);
               if (nodePtr->previous != NULL) {
                  thisLine += ((numBlocks * nodePtr->numLines) + 1);
                  tempNode = nodePtr;
                  nodePtr = nodePtr->previous;

               }
               else {
                  /*
                  **  this is the innermost block but
                  **  not necessarily the right line
                  */
                  thisLine += (numBlocks * nodePtr->numLines);
                  if (lineNum == thisLine) {
                     tempNode = nodePtr;
                     nodePtr = nodePtr->previous;
                  }
                  else
                     tempNode = NULL;
               }
            }
            else {
               thisLine++;
               *memberIndex = lineNum - thisLine;
               /*
               **  we are as close as we can get without looking
               **  at the individual elements of the last node.
               **  ie. array->array->structures
               */
               /* 05/26/94 - Nghia
               ** Fixed PPR 9401 - GPF when inspecting d5[2][0][0][0][0]
               ** of /core/test/l695/ernie/multid.abs
               */
               subNodePtr = nodePtr->subNode;
               if (subNodePtr != NULL) {
                  while ((subNodePtr != NULL) && (lineNum != thisLine)) {
                     thisLine += subNodePtr->numLines;
                     subNodePtr = subNodePtr->next;
                  }
                  *offset += subNodePtr->offset;
               } 
               /* Continue to process the next node */
               tempNode = nodePtr;
               nodePtr = nodePtr->previous;             
            }

            /* Free the processed node and subNode if any */
            if (tempNode != NULL) {
               while (tempNode->subNode != NULL) {
                  subNodePtr = tempNode->subNode->next;
                  if ((error = TFree((LPSTR)tempNode->subNode)) != GOOD)
                     return error;
                  tempNode->subNode = subNodePtr;
               }
               if (tempNode && ((error = TFree((LPSTR)tempNode)) != GOOD))
                  return error;
               tempNode = NULL;
            }
         } /* if (lineNum > thisLine) */
         else {
            /*
            **   check to make sure that nodePtr is NULL
            */
            while (nodePtr != NULL)  {
               tempNode = nodePtr;
               while (tempNode->subNode != NULL) {
                  subNodePtr = tempNode->subNode->next;
                  if ((error = TFree((LPSTR)tempNode->subNode)) != GOOD)
                     return error;
                  tempNode->subNode = subNodePtr;
               }
               nodePtr = nodePtr->previous;
               if ((error = TFree((LPSTR)tempNode)) != GOOD)
                  return error;
            }
         }
      }  /* while */

      if ((lineNum != thisLine) && (lineDif >= 0))
         return ER_VS_ARRAY_MAPADDR_FAIL;
      else {
         *arrayNode = NULL;
         *typeIndex = typeInfo->typeIndex;
      }
   }

   return GOOD;

}

/*************************************************************************
**
** UpdateChildVars
**
*************************************************************************/
RETCODE UpdateChildVars(DESCRIPTOR varId, U16 lineNum,U16 bufferNum,
                        TYPE_INDEX typeIndex,
                        BOOLEAN unionEdit) {

   TYPE_SUBHEADER_TYPE typeInfo;
   TYPE_SUBHEADER_TYPE typeHeader;
   TYPE_INDEX varTypeIndex;
   LOOP_VAR i;
   GET_VAR_ADDR_STRUCT *parentAddr;
   DESCRIPTOR parentId;
   BOOLEAN typeDereferencedPtr=FALSE;
   RETCODE err;

   memset(&typeInfo,'\0',sizeof(typeInfo));
   typeInfo.th.typeName = (LPSTR)typeInfo.typeNameStr;
   typeInfo.typeIndex = typeIndex;
   if ((err = SymGetTypeHeader(typeIndex,
         (TYPE_HEADER_TYPE *)&typeInfo)) != GOOD)
      return err;
   if (( IsPointer(&typeInfo.th)) ||  unionEdit ) {
       
      /*
      **  we have editted a ptr so recalculate the child vars that
      **  have this ptr as their root.
      **  It is also possible that we editted some field of a union
      **  which could change the address of a parent pointer within that
      **  union.  This is not an edit of a pointer directly but indirectly
      **  through the union.  Any children of ptrs in union that were editted
      **  must also be updated. It is alsp possible that we need
      **  to update child vars of dereferenced ptrs to unions or structs.
      **  1/27/95 From Marilyn: we always want to make sure that we
      **  process all the child vars to update their new addresses.
      **  If we bail out with out checking them all, then some 
      **  could display invalid information.  So in the following
      **  loop, instead of returning errors, make sure to process
      **  all children and mark them with invalidAddress if we can
      **  not update the address.
      */
      for (i=0;i < currVarTableSize; i++) {
         if ((varTable[i].used) && (i != varId) &&
            (varTable[i].rootVarId != NOROOT) &&
            (varTable[i].varInfo.selection == COMPONENT_TAG) &&
            ((varTable[i].varInfo.var.component.rootVarId &
                  VS_VARID_MASK) == varId) &&
            (varTable[i].varInfo.var.component.bufferNum == bufferNum) &&
            ((varTable[i].varInfo.var.component.lineNum == lineNum) ||
              unionEdit)) {
            /*
            ** This is a matching child so recalculate the address
            ** based on the same parent again if the parent has a valid
            ** address to start with.
            ** Locate address of the parent which isn't necessarily
            ** the same as the root var. Remember we base the child from
            ** the parent var so use parent var info to calculate the address.
            */
            parentId = varTable[i].varInfo.var.component.parentVarId;
            parentId &= VS_VARID_MASK;
            parentAddr = &varTable[parentId].address;  
            if (!varTable[parentId].invalidAddress) {
               if ((err = AdrDestroyAddress(varTable[i].address.
                     getFixedAddrDesc)) != GOOD)
                  varTable[i].invalidAddress = TRUE;
               /* make sure we know the base type of the child
               ** it could be a typedef and then we would know if it
               ** was a pointer.
               */
               typeDereferencedPtr = varTable[i].typeInfo.typeDereferencedPtr;
               varTypeIndex = varTable[i].typeInfo.typeIndex;
               memcpy(&typeHeader,&varTable[i].typeInfo,sizeof(typeHeader));
               while ((typeHeader.th.typeChoice == COMPLEX_TYPE_CLASS)
                      && (typeHeader.th.t.complexType == TY_TYPE)) {
                  if ((err = SymGetTypeTypeIndex(varTypeIndex,
                        &typeHeader.typeIndex)) != GOOD)
                     varTable[i].invalidAddress = TRUE;
                  if ((err = SymGetTypeHeader(typeHeader.typeIndex,
                        (TYPE_HEADER_TYPE *)&typeHeader)) != GOOD)
                     varTable[i].invalidAddress = TRUE;
                  varTypeIndex = typeHeader.typeIndex;
               }
               if( (
                      !unionEdit && varTable[parentId].dereferencedPtr 
                      && (
                          !(
                             (IsPointer(&typeHeader.th))
                             ||
                             (typeDereferencedPtr)
                           )  
                      )
                   ) ||
                  
                   (unionEdit && !varTable[i].dereferencedPtr) ||
                   (
                      unionEdit
                      &&  (
                          !( 
                             (IsPointer(&typeHeader.th))
                             ||
                             (typeDereferencedPtr)
                           )
                      ) 
                   )
                 ) {
                     
                  /*
                  **  the parent is dereferenced already or it is the
                  **  child of a nondereferencing type, the child of
                  **  such a parent does not need to be dereferenced again
                  **  but needs the address updated.
                  */
                  if ((err = GetAddress(varTable[parentId].registerClass,
                        varTable[parentId].storageClass,
                        varTable[i].typeInfo.byteOffset,
                        parentAddr,
                        &varTable[i].address)) != GOOD)
                     /* if we fail to update the child then
                     ** mark it as invalid so it will display as
                     ** unknown.
                     */
                     varTable[i].invalidAddress = TRUE;
                  // we got a new address so reset the address flag
                  varTable[i].invalidAddress = FALSE;
               }
               else {
                  // NOTES: 11/18/93 - Nghia
                  // Handle SMALL and LARGE pointer differently
                  // Use VarTable[varId].typeInfo.size for the correct size
                  // Use varTable[i].typeInfo.byteOffset for byte offset
                  // from the parent addr.
                  //
                  if ((err = GetPtrDereference(varTable[parentId].registerClass,
                        varTable[parentId].storageClass,
                        &typeInfo, typeInfo.th.t.complexType,
                        varTable[i].typeInfo.byteOffset,
                        varTable[parentId].frameNum,
                        varTable[parentId].frameType,
                        parentAddr,&varTable[i].address)) != GOOD)
                     /* if we fail to update the child address then
                     ** mark it as invalid so that it will display
                     ** as unknown.
                     */
                     varTable[i].invalidAddress = TRUE;
                  // we got a new address so reset the address flag
                  varTable[i].invalidAddress = FALSE;
               }
            } /* if parent has valid address */
            else {
               /* parents address is invalid, therefore the childs
               ** cannot be calculated, so mark it invalid as
               ** well, this way it will display as unknown.
               */
               varTable[i].invalidAddress = TRUE;
            }
         }  /* if matching child */
      }
   }
   return GOOD;
}

/************************************************************************
**
**  IsPointer
**
*************************************************************************/
BOOLEAN IsPointer(TYPE_HEADER_TYPE *typeInfo) {

   if (typeInfo == NULL)
      return FALSE;
   if (typeInfo->typeChoice == COMPLEX_TYPE_CLASS) {
      switch (typeInfo->t.complexType) {
         case TY_SMALL_PTR:
         case TY_LARGE_PTR:
         case TY_16_16_PTR:
         case TY_16_32_PTR:
            return TRUE;
         default:
            return FALSE;
      }
   }
   else {
      if (typeInfo->t.simpleType >= BI_P_UNKNOWN)
         return TRUE;
      else
         return FALSE;
   }
}

/*************************************************************************
**
**  GetPointerEditFieldWidth
**
**************************************************************************/
U16 GetPointerEditFieldWidth(COMPLEX_TYPE complexType) {

   switch(complexType) {
      case TY_SMALL_PTR :
         return ((U16) EDIT_SMALL_PTR_DEFAULT);
      case TY_LARGE_PTR :
         return ((U16) EDIT_LARGE_PTR_DEFAULT);
      case TY_16_16_PTR :
         return ((U16) EDIT_16_16_PTR_DEFAULT);
      case TY_16_32_PTR :
         return ((U16) EDIT_16_32_PTR_DEFAULT);
      default:
         /* Include TY_LARGE_PTR */
         return ((U16) EDIT_LARGE_PTR_DEFAULT);
   }
}

/***********************************************************************
**
**  X86UpdateFuncPtrAddress
**
**  For updating address descriptors for the appropriate segment for
**  deferenced function pointers.
**
**********************************************************************/
RETCODE PRIVATE X86UpdateFuncPtrAddress(DESCRIPTOR address,
                                        TYPE_SUBHEADER_TYPE *typeInfo) {

   RETCODE err;
   ADDR_SEGSEL_TYPE segmentType;
   TYPE_SUBHEADER_TYPE *subType=NULL;
   TYPE_SUBHEADER_TYPE subTypeInfo;
   U16 segmentValue;

   if (procFamily == FAMILY_X86) {
      memset(&subTypeInfo,'\0',sizeof(subTypeInfo));
      subTypeInfo.th.typeName = (LPSTR)subTypeInfo.typeNameStr;
      // check if ptr to function or typedef of function.
      if (typeInfo->next != NULL) {
         subType = typeInfo->next;
         while ((subType->th.typeChoice == COMPLEX_TYPE_CLASS) &&
                (subType->th.t.complexType == TY_TYPE) &&
                (subType->next != NULL)) 
            subType = subType->next;
      }
      else {
         // Retrieve the pointer type information 
         if (typeInfo->typeIndex) {
            if ((err = SymGetTypePointerTypeIndex(typeInfo->typeIndex,
                  &subTypeInfo.typeIndex)) != GOOD)
               return err;
            if ((err = SymGetTypeHeader(subTypeInfo.typeIndex,
                  (TYPE_HEADER_TYPE *)&subTypeInfo)) != GOOD)
               return err;
            subType = &subTypeInfo;
            while ((subType->th.typeChoice == COMPLEX_TYPE_CLASS) &&
                   (subType->th.t.complexType == TY_TYPE)) {
               if ((err = SymGetTypeTypeIndex(subTypeInfo.typeIndex,
                     &subTypeInfo.typeIndex)) != GOOD)
                  return err;
               if ((err - SymGetTypeHeader(subTypeInfo.typeIndex,
                     (TYPE_HEADER_TYPE *)&subTypeInfo)) != GOOD)
                  return err;
            }
         }
      }
      if (subType != NULL) {
         if ((subType->th.typeChoice == COMPLEX_TYPE_CLASS) &&
             ((subType->th.t.complexType == TY_FUNC_DEP) ||
              (subType->th.t.complexType == TY_FUNC_NODEP))) {
            if ((err = AdrGetAddrSegmentSelector(address,&segmentType,
                  &segmentValue)) != GOOD)
               return err;
            if (segmentType == ADDR_USE_DEF_DS)
               // small and large pointers default to the DEF_DS but
               // small or large func pointers should default to CS.
               return (AdrSetAddrSegmentSelector(address,
                       ADDR_USE_CS,NULL));
         }
      }
   }
   return GOOD;
}

/******************************** E O F ***********************************/

