/****************************************************************************
**
**  Name:  varutil.c
**
**  Description:
**     Misc and general routines of variable server.
**
**  Status:  PRELIMINARY 
**
**  $Log:   S:/tbird/mt2_68k/varsrv/varutil.c_v  $
** 
**    Rev 1.3   10 Apr 1998 08:29:56   Winky
** For ID265
** 
**    Rev 1.2   19 Feb 1998 16:11:18   Winky
** Modified UpdateVarTable function.
** 
**    Rev 1.1   12 Aug 1997 11:15:00   gene
** To fix non-updated variable.
** 
**    Rev 1.0   13 Feb 1997 09:08:06   gene
** Initial revision.
** 
**    Rev 1.0   07 Sep 1995 11:25:02   gene
** Initial revision.
** 
**    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_68k/varsrv/varutil.c_v   1.3   10 Apr 1998 08:29:56   Winky  $
**
**  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;

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

VOID GetNthComponent(DESCRIPTOR varId,
                             DESCRIPTOR bufferNum,
                             U16 lineNum,
                             VS_COMPONENT_TYPE **compPtr);
                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/


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

   BOOLEAN found = FALSE;

   if (varTypeInfo->typeChoice == SIMPLE_TYPE_CLASS) {
      *baseTypeTypeInfo = varTypeInfo;
      *typedefTypeInfo = NULL;
   }
   else {
      switch (varTypeInfo->t.complexType) {
         case TY_TYPE:
            /*
            **  we found a typedef!
            **  make sure the subsequent type is not another typedef
            */
            *typedefTypeInfo = varTypeInfo;
            *baseTypeTypeInfo = varTypeInfo->next;
            while (!found) {
               if ((*baseTypeTypeInfo)->typeChoice != SIMPLE_TYPE_CLASS) {
                  if ((*baseTypeTypeInfo)->t.complexType == TY_TYPE)
                     *baseTypeTypeInfo = (*baseTypeTypeInfo)->next;
                  else
                     found = TRUE;
               }
               else
                  found = TRUE;
            }
            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;

   typeHeader.typeName = (LPSTR)typeNameString;
   if ((error = SymGetTypeHeader(*typeIndex,
         (TYPE_HEADER_TYPE *)&typeHeader)) != GOOD)
      return error;
   if (typeHeader.typeChoice == COMPLEX_TYPE_CLASS) {
      while (typeHeader.t.complexType == TY_TYPE) {
         if ((error = SymGetTypeTypeIndex(*typeIndex,typeIndex)) != GOOD)
            return error;
         if ((error = SymGetTypeHeader(*typeIndex,
               (TYPE_HEADER_TYPE *)&typeHeader)) != GOOD)
            return error;
      }
      if ((typeHeader.t.complexType == TY_SMALL_PTR) ||
         (typeHeader.t.complexType == TY_LARGE_PTR)) {
         /*
         ** in other words its a pointer or a typedef of a ptr
         */
         if ((error = GetPtrDereference(rootVar->registerClass,
               rootVar->storageClass,typeHeader.size,byteOffset,
               rootVar->frameNum,rootVar->frameType,&rootVar->address,
               addr)) != GOOD)
            return error;
         *storageClass = GLOBAL_VAR_CLASS;
         typeHeader.typeIndex = *typeIndex;
         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.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,
                          U32 ptrSize,
                          U32 byteOffset,
                          U8 frameNum,
                          U8 frameType,
                          GET_VAR_ADDR_STRUCT *startAddr,
                          GET_VAR_ADDR_STRUCT *newAddr) {

   LPU8 bufPtr;
   U32 offset;
   U32 maxOutputAddress;
   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,
               ptrSize)) != GOOD)
            return error;
      }
      else {
         /*
         ** auto based - Remember stack reads allocate the buffer.
         */
         movmem(startAddr,newAddr,sizeof(*startAddr));
         signedByteOffset = (S32)byteOffset;
         if (newAddr->addrData.getAutoVar.autoVarOffset > 0)
             signedByteOffset = -(signedByteOffset);
         if ((error = StkCalcStkOffset(&newAddr->addrData.getAutoVar.
               autoVarOffset,signedByteOffset)) != GOOD)
            return error;
         if ((error = StkRead(newAddr->addrData.getAutoVar.autoVarOffset,
               ptrSize,frameNum,frameType,&bufPtr)) != GOOD)
            return error;

         // NOTES: Nghia - 10/22/93
         // Handle Short (2 bytes) and Long (4 bytes) pointer
         //
         FlipBuffer(bufPtr, ptrSize);
         if (ptrSize == 4) {
            U32 *offsetLongPtr;
            offsetLongPtr = (U32 *)bufPtr;
            offset = *offsetLongPtr;
         } else {
            U16 *offsetWordPtr;
            offsetWordPtr = (U16 *)bufPtr;
            offset = *offsetWordPtr;
         }
         
         
         // Set Offset of dereference pointer         
         if ((error = AdrCreateAddress(&newAddr->getFixedAddrDesc)) != GOOD)
            return error;
         if ((error = AdrGetMaxOutputAddrOffset(newAddr->getFixedAddrDesc,
               &maxOutputAddress)) != GOOD)
            return error;

         // Mask off invalid bits
         offset &= maxOutputAddress;

         if ((error = AdrSetAddrOffset(newAddr->getFixedAddrDesc,
               offset)) != GOOD) return error;
         if ((error = TFree((LPSTR)bufPtr)) != 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 GOOD;
}

/************************************************************************
**
**  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)->typeChoice == SIMPLE_TYPE_CLASS)
         return;
      if (((*baseTypeInfo)->typeChoice == COMPLEX_TYPE_CLASS) &&
            ((*baseTypeInfo)->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;
   U8 string[20];

   rootVarType = rootTypeInfo->t.complexType;
   if (*compName == '\0') {
      if ((rootVarType == TY_SMALL_PTR) ||
            (rootVarType == TY_LARGE_PTR)) {
         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->typeChoice == COMPLEX_TYPE_CLASS) &&
                  ((baseTypeInfo->t.complexType == TY_SMALL_PTR) ||
                  (baseTypeInfo->t.complexType == TY_LARGE_PTR))) {
               strcat(varName,"*");
            }
         }
      }
   }
   /* If the root type is a deferenced ptr and we are dereferencing
   ** another ptr in a struct. The use the ptr convention -> and drop
   ** the contentsOf convention
   */
   if ((*compName != '\0') && (rootdereferencedPtr) && (*rootVarName == '*'))
      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 :
               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;
   LOOP_VAR i;
   RETCODE error;

   if ((typeInfo->typeChoice == SIMPLE_TYPE_CLASS) ||
       (typeInfo->next == NULL)  ||
       ((typeInfo->typeChoice == COMPLEX_TYPE_CLASS) &&
        (typeInfo->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->typeChoice == SIMPLE_TYPE_CLASS) {
         *offset = 0;
         nodePtr->size = typeInfo->size;
         nodePtr->numLines = memberCount;
         return GOOD;
      }
      switch (typeInfo->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->size;
            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 :
            *offset = 0;
            nodePtr->size = typeInfo->size;
            nodePtr->numLines = memberCount;
            return GOOD;
         case TY_ENUM_C :
            *offset = 0;
            nodePtr->size = typeInfo->size;
            /*
            **  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->size;
            nodePtr->numLines = memberCount;
            return GOOD;
      }
   }
   /* Process Array of type */
   if ((error = SymGetTypeCArray(typeInfo->typeIndex,&cArray)) != GOOD)
      return error;
   /* Check for array of typedef */
   while ((typeInfo->next)->t.complexType == TY_TYPE) {
      typeInfo = typeInfo->next;
   }
   if ((error = MapArrayLine2Offset(typeInfo->next,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->size;
      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,
                        GET_VAR_ADDR_STRUCT *addr,
                        BOOLEAN unionEdit) {

   TYPE_SUBHEADER_TYPE typeInfo;
   LOOP_VAR i;
   RETCODE err;
   /* added by Winky <8/12/97> */
   U32 ptrSize;
   U32 byteOffset;
   VS_COMPONENT_TYPE *compPtr;
   /* eof by Winky <8/12/97> */


   typeInfo.typeName = (LPSTR)typeInfo.typeNameStr;
   if ((err = SymGetTypeHeader(typeIndex,
         (TYPE_HEADER_TYPE *)&typeInfo)) != GOOD)
      return err;
   if (((typeInfo.typeChoice == COMPLEX_TYPE_CLASS) &&
      ((typeInfo.t.complexType == TY_SMALL_PTR) ||
       (typeInfo.t.complexType == TY_LARGE_PTR))) ||  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.
      */
      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 ((err = AdrDestroyAddress(varTable[i].address.
                  getFixedAddrDesc)) != GOOD)
               return err;
            if ((!unionEdit && varTable[varId].dereferencedPtr &&
                   !( (varTable[i].typeInfo.typeChoice == COMPLEX_TYPE_CLASS &&
                    (varTable[i].typeInfo.t.complexType == TY_LARGE_PTR ||
                    varTable[i].typeInfo.t.complexType == TY_SMALL_PTR)) ||
                    (varTable[i].dereferencedPtr) )) ||
                (unionEdit && !varTable[i].dereferencedPtr) ||
                (unionEdit && 
                    !( varTable[i].typeInfo.typeChoice == COMPLEX_TYPE_CLASS &&
                     (varTable[i].typeInfo.t.complexType == TY_SMALL_PTR ||
                     varTable[i].typeInfo.t.complexType == TY_LARGE_PTR) ))) {
               /*
               **  the parent is a dereferenced already or it 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[varId].registerClass,
                     varTable[varId].storageClass,0,addr,
                     &varTable[i].address)) != GOOD)
                  return err;
            }
            else {
               // NOTES: 11/18/93 - Nghia
               // Handle SMALL and LARGE pointer differently
               // Use VarTable[varId].typeInfo.size for the correct size
               //
               if ((err = GetPtrDereference(varTable[varId].registerClass,
                     varTable[varId].storageClass,
                     typeInfo.size, 0,
                     varTable[varId].frameNum,varTable[varId].frameType,
                     addr,&varTable[i].address)) != GOOD)
                  return err;
            }
         }
      }
   }
   /* added by Winky <8/12/97> */
   else
   {
   if ((typeInfo.typeChoice == COMPLEX_TYPE_CLASS) &&
       (varTable[varId].compListPtr != NULL)) {

      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)) {

            // if ((err = AdrDestroyAddress(varTable[i].address.
            //      getFixedAddrDesc)) != GOOD)
            //    return err;

            GetNthComponent(varId, bufferNum, lineNum, &compPtr);

            if (compPtr != NULL && //Hera 4/9/98 Only Pointer and Reference need Dereference
                   (compPtr->typeInfo.typeChoice == COMPLEX_TYPE_CLASS &&
                    compPtr->typeInfo.t.complexType == TY_LARGE_PTR  ||
                    compPtr->typeInfo.t.complexType == TY_SMALL_PTR )) {
               ptrSize=compPtr->typeInfo.size;
               byteOffset = compPtr->offset;

               if ((err = GetPtrDereference(varTable[varId].registerClass,
                     varTable[varId].storageClass,
                     ptrSize,byteOffset,
                     varTable[varId].frameNum,varTable[varId].frameType,
                     addr,&varTable[i].address)) != GOOD)
                  return err;
               }
            }
         }
      }
   }
   /* eof by Winky <8/12/97> */
   return GOOD;
}
/******************************** E O F ***********************************/

