Source

daybodep / daybodep_stringlist.c

Full commit
/*
    Daybo Logic Dependency tool
    Copyright (C) 2001-2003  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,
  57 Alderwood Parc,
  Penryn,
  Kernow,
  United Kingdom

  TR10 8RL
*/

#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);
static void DestroyNode(struct string_list_node* PStringListNode); /* Does not fix any node linkage, frees string inside node etc. then the node itself, PStringListNode is not valid after the call returns */
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);
  actual = ChecksumCalculate(PStringListNode->dynamicString); /* the checksummer can handle it if DynamicString is NULL, so no worries */
  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? */
  FreeNodeString(PStringListNode); /* Release the string the node is managing */
  free(PStringListNode); /* Release the node, pointer is no longer valid for caller */
}
/*-------------------------------------------------------------------------*/
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( !strcmp(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 */
}
/*-------------------------------------------------------------------------*/