////////////////////////////////////////////////////////////////////////////////
//
// propmisc.c
//
// Misc. Property set rotuines
//
// Change history:
//
// Date         Who             What
// --------------------------------------------------------------------------
// 07/30/94     B. Wentz        Created file
//
////////////////////////////////////////////////////////////////////////////////

#include "priv.h"
#pragma hdrstop



////////////////////////////////////////////////////////////////////////////////
//
// LpllCreateList
//
// Purpose:
//  Create a linked list with dwc elements.
//
////////////////////////////////////////////////////////////////////////////////
LPLLIST
LpllCreate
  (LPLLIST *lplpll,                     // Head
   LPLLCACHE lpllcache,                 // Cache
   DWORD dwc,                           // Number of nodes to create
   DWORD cbNode)                        // Size of each node
{
  LPLLIST lpllT;
  LPLLIST lpllCur;

  if ((lplpll == NULL) ||
      (dwc < 1)        ||
      (cbNode < sizeof(LLIST)))
    return NULL;

  lpllCur = *lplpll = PvMemAlloc(cbNode);
  if (lpllCur == NULL)
  {
    return NULL;
  }
  FillBuf (lpllCur, 0, cbNode);

  lpllCur->lpllistPrev = NULL;
  dwc--;

  while (dwc)
  {
    lpllT = PvMemAlloc(cbNode);
    if (lpllT == NULL)
      goto Fail;

    FillBuf (lpllT, 0, cbNode);
    lpllT->lpllistPrev = lpllCur;
    lpllCur->lpllistNext = lpllT;
    lpllCur = lpllT;
    dwc--;
  } // while

  lpllCur->lpllistNext = NULL;
  lpllcache->lpllist = NULL;

  return *lplpll;

Fail :

  lpllCur = *lplpll;
  while (lpllCur != NULL)
  {
    lpllT = lpllCur;
    lpllCur = lpllCur->lpllistNext;
    VFreeMemP(lpllT, cbNode);
  }

  return NULL;

} // LpllCreateList


////////////////////////////////////////////////////////////////////////////////
//
// LpllGetNode
//
// Purpose:
//  Gets a node from the list
//
////////////////////////////////////////////////////////////////////////////////
LPLLIST
LpllGetNode
  (LPLLIST lpllist,             // The head
   LPLLCACHE lpllcache,         // The cache
   DWORD idw)                   // Index of node to get -- 1 based
{
  DWORD i = idw;

  if ((lpllcache->lpllist != NULL) && (lpllcache->idw == idw))
  {
    return lpllcache->lpllist;
  }

  while ((i > 1) && (lpllist != NULL))
  {
    lpllist = lpllist->lpllistNext;
    i--;
  }

  if (lpllist != NULL)
  {
    lpllcache->idw = idw;
    lpllcache->lpllist = lpllist;
  }

  return lpllist;

} // LpllGetNode


////////////////////////////////////////////////////////////////////////////////
//
// LpllDeleteNode
//
// Purpose:
//  Delete a node from the list
//
////////////////////////////////////////////////////////////////////////////////
LPLLIST
LpllDeleteNode
  (LPLLIST lpllist,                     // Head
   LPLLCACHE lpllcache,                 // Cache
   DWORD idw,                           // Index -- 1 based
   DWORD cbNode,                        // Size of node
   void (*lpfnFreeNode)(LPLLIST)     // Free a node
   )
{
  LPLLIST lpT;
  LPLLIST lpNext;

  BOOL fHead;

    // Check the cache
  if ((lpllcache->lpllist != NULL) && (lpllcache->idw == idw))
  {
    lpT = lpllcache->lpllist;
    lpllcache->lpllist = NULL;
  }
  else
  {
    lpT = LpllGetNode (lpllist, lpllcache, idw);
  }

  if (lpT == NULL)      // We couldn't find the node
  {
         return lpT;
  }

  fHead = lpT->lpllistPrev == NULL;

    // Delete the node from the list
  if (lpT->lpllistPrev != NULL)
  {
    lpT->lpllistPrev->lpllistNext = lpT->lpllistNext;
  }

  if ((lpNext = lpT->lpllistNext) != NULL)
  {
    lpT->lpllistNext->lpllistPrev = lpT->lpllistPrev;
  }

    // Delete the string & node
  (*lpfnFreeNode) (lpT);
  VFreeMemP(lpT, cbNode);

    // If the head was deleted, return the new one.
  return (fHead ? lpNext : lpllist);

} // LpllDeleteNode


////////////////////////////////////////////////////////////////////////////////
//
// LpllInsertNode
//
// Purpose:
//  Insert a node into the list
//
////////////////////////////////////////////////////////////////////////////////
LPLLIST PASCAL
LpllInsertNode
  (LPLLIST lpllist,                     // Head
   LPLLCACHE lpllcache,                 // Cache
   DWORD idw,                           // index
   DWORD cbNode)                        // Size of node
{
  LPLLIST lpT;
  LPLLIST lpOrigHead;
  BOOL fHead;
  DWORD idwOrig;

  if ((lpOrigHead = lpllist) == NULL)
  {
    return NULL;
  }

  idwOrig = idw;

  Assert ((idw > 0));
  idw--;
  while ((idw) && (lpllist->lpllistNext != NULL))
  {
    lpllist = lpllist->lpllistNext;
    idw--;
  }

  lpT = PvMemAlloc(cbNode);
  if (lpT == NULL)
  {
    return NULL;
  }
  FillBuf (lpT, 0, cbNode);

    // If the new node was to be inserted at the end, idw would not
    // be zero, the while loop would have fallen out because Next was NULL
  if (idw)
  {
    fHead = FALSE;
    lpT->lpllistPrev = lpllist;
    lpT->lpllistNext = NULL;
    lpllist->lpllistNext = lpT;
  }
  else
  {
    fHead = (lpllist == lpOrigHead);

    lpT->lpllistPrev = lpllist->lpllistPrev;
    if (lpllist->lpllistPrev != NULL)
    {
      lpllist->lpllistPrev->lpllistNext = lpT;
    }
    lpT->lpllistNext = lpllist;
    lpllist->lpllistPrev = lpT;
  }

    // Update the cache
  lpllcache->idw = idwOrig;
  lpllcache->lpllist = lpT;

  return (fHead ? lpT : lpOrigHead);

} // LpllInsertNode

