/*---------------------------------------------------------------------------
                      D Y N A M I C  A R R A Y
                      
   Implementation file for a dynamically resizing array of void pointers.
   
   Mark Koennecke, September 1997
                    
   copyright: see copyright.h
   
-----------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include "fortify.h"
#include "sdynar.h"
#include "sdynar.i"

/*---------------------------------------------------------------------------*/
   pDynar CreateDynar(int iStart, int iEnd, int iGrain, 
                      void (*DataFree)(void *pData))
   {
     pDynar pNew = NULL;
     int iSize;
     
     pNew = (pDynar)malloc(sizeof(Dynar));
     if(!pNew)
     {
       return NULL;
     }
     memset(pNew, 0, sizeof(Dynar));
     
     pNew->iStart = iStart;
     pNew->iEnd   = iEnd;
     pNew->iGrain = iGrain;
     pNew->DataFree = DataFree;
     iSize = iEnd - iStart;
     assert(iSize > 0);
     pNew->pArray = (void **)malloc(iSize * sizeof(void *));
     if(!pNew->pArray)
     {
       free(pNew);
       return NULL;
     }
     memset(pNew->pArray,0,iSize * sizeof(void *));
     return pNew;
   }             
/*----------------------------------------------------------------------------*/
   void DeleteDynar(pDynar self)
   {
     int i, iSize;
     
     assert(self);
     
     iSize = self->iEnd - self->iStart;
     for(i = 0; i < iSize; i++)
     {
       if(self->pArray[i])
       {
         if(self->DataFree)
         {
           self->DataFree(self->pArray[i]);
         }
       }
     }
     free(self->pArray);
     free(self);
   }
/*---------------------------------------------------------------------------*/
  static int DynarResize(pDynar self, int iRequest)
  {
     void **pNew = NULL;
     int i, iNewStart, iNewEnd, iOldSize, iNewSize, iOffset;

     assert(self);
     iOldSize = self->iEnd - self->iStart;
     
     iNewStart = self->iStart;
     iNewEnd = self->iEnd;
     if(iRequest <= self->iStart)
     {
       iNewStart -= self->iGrain;
     }
     if(iRequest >= (self->iEnd - 1))
     {
       iNewEnd += self->iGrain;
     }
     iNewSize = iNewEnd - iNewStart;
     
     pNew = (void **)malloc(iNewSize * sizeof(void *));
     if(!pNew)
     {
       return 0;
     }
     memset(pNew,0,iNewSize*sizeof(void *));
     
     iOffset = self->iStart - iNewStart;
     if(iOffset < 0)
     {
       iOffset = - iOffset;
     }
     for(i = 0; i < iOldSize; i++)
     {
        pNew[i+iOffset] = self->pArray[i];
     }
     self->iStart = iNewStart;
     self->iEnd = iNewEnd;
     free(self->pArray);
     self->pArray = pNew;
     return 1;
  }                                   
/*----------------------------------------------------------------------------*/  
  int DynarPut(pDynar self, int iIndex, void *pData)
  {
     int iReal, iRet;
     
     assert(self);
     
     if( (iIndex < self->iStart) ||  (iIndex > self->iEnd -1) )
     {
       iRet = DynarResize(self,iIndex);
       if(!iRet)
       {
         return 0;
       }
     }
     
     iReal = iIndex - self->iStart;
     if(self->pArray[iReal])
     {
       if(self->DataFree)
       {
         self->DataFree(self->pArray[iReal]);
       }
     }
     self->pArray[iReal] = pData;
     return 1; 
  }
/*-------------------------------------------------------------------------*/
  int DynarPutCopy(pDynar self, int iIndex, void *pBuffer, int iDataLen)
  {
    char *pPtr = NULL;
    
    pPtr = (char *)malloc(iDataLen);
    if(!pPtr)
    {
      return 0;
    }
    memcpy(pPtr,pBuffer,iDataLen);
    return DynarPut(self,iIndex,pPtr);
  }  
/*--------------------------------------------------------------------------*/
  int DynarReplace(pDynar self, int iIndex, void *pData, int iDataLen)
  {
     int iReal, iRet;
     
     assert(self);

     if( (iIndex < self->iStart) ||  (iIndex >= self->iEnd -1) )
     {
       iRet = DynarResize(self,iIndex);
       if(!iRet)
       {
         return 0;
       }
     }

     iReal = iIndex - self->iStart;
     if(self->pArray[iReal])
     {
        memcpy(self->pArray[iReal],pData,iDataLen);
        return 1;
     }
     else
     {
       return DynarPutCopy(self,iIndex,pData,iDataLen);
     }
  }
/*---------------------------------------------------------------------------*/  
  int DynarGet(pDynar self, int iIndex, void **pData)
  {
     int iReal;
     
     assert(self);
     
     iReal = iIndex - self->iStart;
     *pData = self->pArray[iReal];
     return 1; 
  }
/*-------------------------------------------------------------------------*/
  int DynarGetCopy(pDynar self, int iIndex, void *pData, int iDataLen)
  {
     int iReal;
     
     assert(self);
     
     iReal = iIndex - self->iStart;
     memcpy(pData,self->pArray[iReal],iDataLen);
     return 1; 
  }
