Source

daybodep / dstrlist.c

/*
    Daybo Logic Dependency tool
    Copyright (C) 2001-2006  David Duncan Ross Palmer, Daybo Logic.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


  Daybo Logic,
  Flat 2 Barker Court,
  Victoria Avenue,
  Redfield,
  Bristol,
  United Kingdom

  BS5 9NW
*/

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifdef HDRSTOP
# pragma hdrstop
#endif /*HDRSTOP*/

#include "daybodep.h"
/*-------------------------------------------------------------------------*/
/* Functions for handling nodes */
static bool VerifyNode(
  struct string_list_node *PStringListNode
);

static bool SetNodeString(
  struct string_list_node *PStringListNode,
  const char *NewStr
);

static void FreeNodeString(
  struct string_list_node *PStringListNode
);

static struct string_list_node *CreateNode(
  const char *InitialString
);

static void InitNode(
  struct string_list_node *PStringListNode
);

/*
  DestroyNode() does no fix any node linkage, frees string inside node etc.
  then frees the node itself.  PStringListNode is not valid after the
  function returns.
*/
static void DestroyNode(
  struct string_list_node *PStringListNode
);

static struct string_list_node *FindEndNode(
  struct string_list *PStringList
);

static struct string_list_node *NodeFromPos(
  struct string_list *PStringList,
  unsigned int Pos
);

/* Member functions */
static bool l_Add(
  struct string_list *Obj,
  const char *NewString
);

static unsigned int l_Count(
  const struct string_list *Obj
);

static void l_Clear(
  struct string_list *Obj
);
static const char *l_GetString(
  const struct string_list *Obj,
  const unsigned int Pos
);

static bool l_DelByPos(
  struct string_list *Obj,
  const unsigned int Pos
);

static bool l_StringExists(
  struct string_list *Obj,
  const char *S
);
/*-------------------------------------------------------------------------*/
static bool VerifyNode(
  struct string_list_node *PStringListNode
)
{
  CHECKSUM actual;
  bool result = false;

  assert(PStringListNode);
  /* The checksummer can accept NULL, so no worries */
  actual = ChecksumCalculate(PStringListNode->dynamicString);
  if ( ChecksumCompare(&actual, &PStringListNode->checkSum) == chkdEqual )
    result = true; /* OK! */

  assert(result); /* Crash if debugging */
  return result;
}
/*-------------------------------------------------------------------------*/
static bool SetNodeString(
  struct string_list_node *PStringListNode,
  const char *NewStr
)
{
  bool ok = false;
  assert(PStringListNode);
  FreeNodeString(PStringListNode); /* Release old string if there is one */
  if ( NewStr ) { /* New one to assign? */
    PStringListNode->dynamicString = (char*)malloc( strlen(NewStr) + 1 );
    if ( PStringListNode->dynamicString ) {
      strcpy(PStringListNode->dynamicString, NewStr);
      ok = true;
    }
    /* Update the sum */
    PStringListNode->checkSum = ChecksumCalculate(
      PStringListNode->dynamicString
    );
  }
  return ok;
}
/*-------------------------------------------------------------------------*/
static void FreeNodeString(
  struct string_list_node *PStringListNode
)
{
  if ( PStringListNode ) {
    if ( PStringListNode->dynamicString ) {
      free(PStringListNode->dynamicString);
      PStringListNode->dynamicString = NULL;
      ChecksumAssign(&PStringListNode->checkSum, NULL);
    }
  }
}
/*-------------------------------------------------------------------------*/
static struct string_list_node *CreateNode(
  const char *InitialString
)
{
  struct string_list_node *newNode =
    (struct string_list_node*)malloc( sizeof(struct string_list_node) );

  if ( newNode ) {
    InitNode(newNode);
    if ( InitialString ) {
      if ( !SetNodeString(newNode, InitialString) ) {
        /* Failed, so release the node again */
        DestroyNode(newNode);
        newNode = NULL;
      }
    }
  }
  return newNode;
}
/*-------------------------------------------------------------------------*/
static void InitNode(
  struct string_list_node *PStringListNode
)
{
  assert(PStringListNode);
  memset(PStringListNode, 0, sizeof(struct string_list_node));
  return;
}
/*-------------------------------------------------------------------------*/
static void DestroyNode(
  struct string_list_node *PStringListNode
)
{
  assert(PStringListNode); /* Valid pointer? */
  /* Release the string the node is managing */
  FreeNodeString(PStringListNode);
  /* Release the node.  Pointer is no longer valis for caller */
  free(PStringListNode);
}
/*-------------------------------------------------------------------------*/
static struct string_list_node* FindEndNode(
  struct string_list *PStringList
)
{
  struct string_list_node* currentNode;

  for (
    currentNode = PStringList->base;
    currentNode;
    currentNode = currentNode->next
  ) {
    if ( !currentNode->next ) /* This is the last one! */
      return currentNode;
  }
  assert(!currentNode); /* Ensure it's NULL, I'm tired */
  return currentNode; /* NULL */
}
/*-------------------------------------------------------------------------*/
static struct string_list_node* NodeFromPos(
  struct string_list *PStringList,
  unsigned int Pos
)
{
  struct string_list_node* currentNode;
  unsigned int i = 0U;

  for (
    currentNode = PStringList->base;
    currentNode;
    currentNode = currentNode->next
  ) {
    if ( Pos == i ) { /* Found the right place */
      if ( !VerifyNode(currentNode) )
        currentNode = NULL; /* Hide corruption */
      return currentNode;
    }
  }
  assert(!currentNode); /* Ensure it's NULL, I'm tired */
  return currentNode; /* NULL */
}
/*-------------------------------------------------------------------------*/
void S_StringList_Construct(
  struct string_list *Obj
)
{
  assert(Obj);
#ifndef NDEBUG
  memset(Obj, 0, sizeof(struct string_list)); /* Safety */
#endif /*!DEBUG*/

  /* Initialise private members */
  Obj->base = NULL; /* No free list */
  Obj->count = 0U; /* No nodes */

  /* Link member functions */
  Obj->Add = l_Add;
  Obj->Count = l_Count;
  Obj->Clear = l_Clear;
  Obj->GetString = l_GetString;
  Obj->DelByPos = l_DelByPos;
  Obj->StringExists = l_StringExists;
}
/*-------------------------------------------------------------------------*/
void S_StringList_Destruct(
  struct string_list *Obj
)
{
  assert(Obj);
  l_Clear(Obj); /* clear out the free list */
  return;
}
/*-------------------------------------------------------------------------*/
static bool l_StringExists(
  struct string_list *Obj,
  const char *S
)
{
  struct string_list_node *n;

  assert(Obj && S);
  for(n = Obj->base; n; n = n->next)
    if( !Compare(S, n->dynamicString) )
      return true;
  return false;
}
/*-------------------------------------------------------------------------*/
static bool l_Add(
  struct string_list *Obj,
  const char *NewString
)
{
  struct string_list_node* newNode;
  assert(Obj && NewString);
  newNode = CreateNode(NewString);
  if ( newNode ) {
    struct string_list_node* lastNode = FindEndNode(Obj);
    if ( !lastNode ) /* No previous nodes */
      Obj->base = newNode; /* Assign the new node to the base */
    else /* Previous nodes exist */
      lastNode->next = newNode; /* Tack the new node onto the end */

    Obj->count++; /* Increase cached count of nodes */
    return true;
  }
  return false;
}
/*-------------------------------------------------------------------------*/
static unsigned int l_Count(
  const struct string_list *Obj
)
{
  assert(Obj);
  return Obj->count;
}
/*-------------------------------------------------------------------------*/
static void l_Clear(
  struct string_list *Obj
)
{
  assert(Obj);
  while ( Obj->count ) /* Until empty... */
    l_DelByPos(Obj, 0); /* Delete first node */
}
/*-------------------------------------------------------------------------*/
static const char* l_GetString(
  const struct string_list *Obj,
  const unsigned int Pos
)
{
  struct string_list_node* node;
  unsigned int i = 0U;
  assert(Obj);

  for ( node = Obj->base; node; node = node->next ) {
    if ( i++ == Pos )
      break;
  }

  if ( node ) {
    VerifyNode(node);
    return node->dynamicString; /* Give the user the string */
  }
  return NULL;
}
/*-------------------------------------------------------------------------*/
static bool l_DelByPos(
  struct string_list *Obj,
  const unsigned int Pos
)
{
  struct string_list_node* tnode; /* Target node, node to kill */
  unsigned int i = 0U; /* Holds index of node above one being removed */
  assert(Obj);

  tnode = Obj->base;
  while ( tnode ) {
    if ( i == Pos ) { /* Node to kill? */
      if ( i ) { /* There's a previous node before us? */
        struct string_list_node* prevNode = NodeFromPos(Obj, i-1);
        assert(prevNode); /* Never happen I hope */
        prevNode->next = tnode->next;
      }
      else { /* No previous node */
        Obj->base = tnode->next; /* Relinking of base */
      }
      DestroyNode(tnode);
      Obj->count--; /* Decrease cached count of nodes */
      return true; /* Deleted successfully */
    }
    else { /* Not the node to kill */
      tnode = tnode->next; /* Transcend */
    }
    i++;
  }
  return false; /* Invalid pos */
}
/*-------------------------------------------------------------------------*/
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.