strcollection.c

J

jacob navia

/*------------------------------------------------------------------------
Module: strcollection.c
Author: jacob
Project: Containers
State:
Creation Date:
Description: Implements the string collection container.
Added fixes from Gerome. Oct. 20 2005
------------------------------------------------------------------------*/
#include "containers.h"
static int GetCount( StringCollection *SC);
static int IsReadOnly( StringCollection *SC);
static int SetReadOnly( StringCollection *SC,int newval);
static int Add( StringCollection *SC,char *newval);
static int AddRange( StringCollection *SC,char **newvalues);
static int Clear( StringCollection *SC);
static bool Contains( StringCollection *SC,char *str);
static char **CopyTo( StringCollection *SC);
static int IndexOf( StringCollection *SC,char *SearchedString);
static int Insert( StringCollection *SC,char *);
static int InsertAt( StringCollection *SC,int idx,char *newval);
static char *IndexAt( StringCollection *SC,int idx);
static int Remove( StringCollection *SC,char *);
static int RemoveAt( StringCollection *SC,int idx);
static int Finalize( StringCollection *SC);
static int GetCapacity( StringCollection *SC);
static bool SetCapacity( StringCollection *SC,int newCapacity);
static void Apply(StringCollection *SC,int(*Applyfn)(char *,void *),void *arg);
static int *Map(StringCollection *SC,int (*Applyfn)(char *));
static int Push(StringCollection *SC,char *str);
static char *Pop(StringCollection *SC);
static char *ReplaceAt(StringCollection *SC,int idx,char *newval);
static int IsCaseSensitive(StringCollection *SC);
static int SetCaseSensitive(StringCollection *SC,int newval);
static bool Equal(StringCollection *SC1,StringCollection *SC2);
static StringCollection *Copy(StringCollection *SC);
static StringCollectionInterface lpVtblSC = {
GetCount, IsReadOnly, SetReadOnly, Add, AddRange, Clear, Contains,
CopyTo, IndexOf, Insert, InsertAt, IndexAt, Remove, RemoveAt,
Finalize, GetCapacity, SetCapacity, Apply, Map, Push, Pop, ReplaceAt,
IsCaseSensitive,
SetCaseSensitive,Equal,Copy,
};

#ifndef DEFAULT_START_SIZE
#define DEFAULT_START_SIZE 20
#endif
/*------------------------------------------------------------------------
Procedure: DuplicateString ID:1
Purpose: Functional equivalent of strdup with added argument
in case of error
Input: The string to duplicate and the name of the calling function
Output: The duplicated string
Errors: Duplication of NULL is allowed and returns NULL. If no more
memory is available the error function is called.
------------------------------------------------------------------------*/
static char * DuplicateString(char *str,const char *fnname)
{
char *result;
if (str == NULL) return NULL;
result = MALLOC(strlen(str)+1);
if (result == NULL) {
ContainerRaiseError(fnname,CONTAINER_ERROR_NOMEMORY);
return NULL;
}
strcpy(result,str);
return result;
}

#define SC_READONLY 1
#define SC_IGNORECASE 2
#define CHUNKSIZE 20

/*------------------------------------------------------------------------
Procedure: newStringCollection ID:1
Purpose: Creates a new string collection
Input: The initial start size of the collection
Output: A pointer to the new collection or NULL
Errors: If no more memory is available it returns NULL
after calling the error function.
------------------------------------------------------------------------*/
StringCollection *newStringCollection(int startsize)
{
StringCollection *result;

result = MALLOC(sizeof(*result));
if (result == NULL) {
ContainerRaiseError("newStringCollection",CONTAINER_ERROR_NOMEMORY);
return NULL;
}
memset(result,0,sizeof(StringCollection));
result->lpVtbl = &lpVtblSC;
if (startsize > 0) {
result->contents = MALLOC(startsize*sizeof(char *));
if (result->contents == NULL) {
ContainerRaiseError("newStringCollection",CONTAINER_ERROR_NOMEMORY);
FREE(result);
result=NULL;
}
else {
memset(result->contents,0,sizeof(char *)*startsize);
result->capacity = startsize;
result->RaiseError = ContainerRaiseError;
}
}
return result;
}

static int GetCount(struct _StringCollection *SC){ return SC->count;}

/*------------------------------------------------------------------------
Procedure: IsReadOnly ID:1
Purpose: Reads the read-only flag
Input: The collection
Output: the state of the flag
Errors: None
------------------------------------------------------------------------*/
static int IsReadOnly(StringCollection *SC)
{
return (SC->Flags & SC_READONLY) ? 1 : 0;
}

/*------------------------------------------------------------------------
Procedure: SetReadOnly ID:1
Purpose: Setsq the value of the read only flag
Input: The collection to be changed
Output: The old value of the flag
Errors: None
------------------------------------------------------------------------*/
static int SetReadOnly(StringCollection *SC,int newval)
{
int oldval = SC->Flags & SC_READONLY ? 1 : 0;
if (newval)
SC->Flags |= SC_READONLY;
else
SC->Flags &= ~SC_READONLY;
return oldval;
}

/*------------------------------------------------------------------------
Procedure: IsCaseSensitive ID:1
Purpose: Reads the case sensitive flag
Input: The collection
Output: The state of the flag
Errors: None
------------------------------------------------------------------------*/
static int IsCaseSensitive(StringCollection *SC)
{
return (SC->Flags & SC_IGNORECASE) ? 0 : 1;
}

/*------------------------------------------------------------------------
Procedure: SetReadOnly ID:1
Purpose: Setsq the value of the read only flag
Input: The collection to be changed
Output: The old value of the flag
Errors: None
------------------------------------------------------------------------*/
static int SetCaseSensitive(StringCollection *SC,int newval)
{
int result = (SC->Flags & SC_IGNORECASE) ? 0 : 1;
if (newval) SC->Flags &= ~SC_IGNORECASE;
else
SC->Flags |= SC_IGNORECASE;
return result;
}

/*------------------------------------------------------------------------
Procedure: Resize ID:1
Purpose: Grows a string collection by CHUNKSIZE
Input: The collection
Output: One if successfull, zero othewise
Errors: If no more memory is available, nothing is changed
and returns zero
------------------------------------------------------------------------*/
static int Resize(StringCollection *SC)
{
int newcapacity = SC->capacity + CHUNKSIZE;
char **oldcontents = SC->contents;
SC->contents = MALLOC(newcapacity*sizeof(char *));
if (SC->contents == NULL) {
SC->contents = oldcontents;
return 0;
}
memset(SC->contents,0,sizeof(char *)*newcapacity);
memcpy(SC->contents,oldcontents,SC->count*sizeof(char *));
SC->capacity = newcapacity;
FREE(oldcontents);
return 1;
}

/*------------------------------------------------------------------------
Procedure: Add ID:1
Purpose: Adds a string to the string collection.
Input: The collection and the string to be added to it
Output: Number of items in the collection or <= 0 if error
Errors:
------------------------------------------------------------------------*/
static int Add(StringCollection *SC,char *newval)
{
if (SC->Flags & SC_READONLY)
return CONTAINER_ERROR_READONLY;
if (SC->count >= SC->capacity) {
int r = Resize(SC);
if (r <= 0)
return r;
}

if (newval) {
SC->contents[SC->count] = DuplicateString(newval,"Add");
if (SC->contents[SC->count] == NULL) {
return 0;
}
}
else
SC->contents[SC->count] = NULL;
return ++SC->count;
}

static int AddRange(StringCollection *SC,char **data){
int i = 0,c;
if (SC->Flags & SC_READONLY)
return CONTAINER_ERROR_READONLY;
c = SC->count;
while (data != NULL) {
int r = Add(SC,data);
if (r <= 0) {
return r;
}
i++;
}
return i;
}

static int Clear(StringCollection *SC){
int oldval = SC->count,i;
if (SC->Flags & SC_READONLY)
return CONTAINER_ERROR_READONLY;
for (i=0; i<SC->count;i++) {
FREE(SC->contents);
SC->contents = NULL;
}
SC->count = 0;
return oldval;
}

static bool Contains(StringCollection *SC,char *str){
int c,i;
if (str == NULL) return 0;
c = *str;
if ((SC->Flags & SC_IGNORECASE) == 0) {
for (i=0; i<SC->count;i++) {
if (c == SC->contents[0] && !strcmp(SC->contents,str)) return 1;
}
}
else {
for (i = 0; i<SC->count;i++) {
if (!stricmp(SC->contents,str))
return 1;
}
}
return 0;
}

static char **CopyTo(StringCollection *SC)
{
char **result = MALLOC((1+SC->count)*sizeof(char *));
int i;
if (result == NULL)
return NULL;
for (i=0; i<SC->count;i++) {
result = DuplicateString(SC->contents,"Copy");
}
result = NULL;
return result;
}

static int IndexOf(StringCollection *SC,char *str){
int i;
int (*cmpfn)(const char *,const char *);

if (SC->Flags & SC_IGNORECASE) {
cmpfn = stricmp;
}
else cmpfn = strcmp;

for (i=0; i<SC->count;i++) {
if (!cmpfn(SC->contents,str)) {
return i;
}
}
return -1;
}

static char *IndexAt(StringCollection *SC,int idx)
{
if (idx >=SC->count || idx < 0)
return NULL;
return SC->contents[idx];
}

static int InsertAt(StringCollection *SC,int idx,char *newval)
{
char *p;
if (SC->Flags & SC_READONLY)
return CONTAINER_ERROR_READONLY;
if (SC->count >= (SC->capacity-1)) {
int r = Resize(SC);
if (r <= 0)
return r;
}
if (idx < 0)
return CONTAINER_ERROR_BADARG;
if (idx >= SC->count)
return CONTAINER_ERROR_INDEX;
p = DuplicateString(newval,"InsertAt");
if (p == NULL) {
return CONTAINER_ERROR_NOMEMORY;
}

if (idx == 0) {
if (SC->count > 0)
memmove(SC->contents+1,SC->contents,SC->count*sizeof(char *));
SC->contents[0] = p;
}
else if (idx == SC->count) {
SC->contents[idx] = p;
}
else if (idx < SC->count) {
memmove(SC->contents+idx+1,SC->contents+idx,(SC->count-idx+1)*sizeof(char *));
SC->contents[idx] = p;
}
return ++SC->count;
}

static int Insert(StringCollection *SC,char *newval)
{
return InsertAt(SC,0,newval);
}

static int RemoveAt(StringCollection *SC,int idx)
{
if (idx >= SC->count || idx < 0 )
return CONTAINER_ERROR_INDEX;
if (SC->Flags & SC_READONLY)
return CONTAINER_ERROR_READONLY;
/* Test for remove of an empty collection */
if (SC->count == 0)
return 0;
FREE(SC->contents[idx]);
if (idx < (SC->count-1)) {
memmove(SC->contents+idx,SC->contents+idx+1,(SC->count-idx)*sizeof(char *));
}
SC->contents[SC->count-1]=NULL;
return --SC->count;
}

static int Remove(StringCollection *SC,char *str)
{
int idx = IndexOf(SC,str);
if (idx < 0)
return CONTAINER_ERROR_NOTFOUND;
return RemoveAt(SC,idx);
}

static int Push(StringCollection *SC,char *str)
{
char *r;
if (SC->Flags&SC_READONLY)
return 0;
if (SC->count >= SC->capacity-1) {
int r = Resize(SC);
if (r <= 0)
return r;
}
r = DuplicateString(str,"Push");
if (r == NULL)
return 0;
SC->contents[SC->count++] = r;
return SC->count;
}

static char * Pop(StringCollection *SC)
{
char *result;
if ((SC->Flags&SC_READONLY) || SC->count == 0)
return NULL;
SC->count--;
result = SC->contents[SC->count];
SC->contents[SC->count] = NULL;
return result;
}

static int Finalize(StringCollection *SC){
int result = SC->count,i;
for (i=0; i<SC->count;i++) {
FREE(SC->contents);
}
FREE(SC->contents);
FREE( SC);
return result;
}

static int GetCapacity(StringCollection *SC)
{
return SC->capacity;
}

static bool SetCapacity(StringCollection *SC,int newCapacity)
{
if (SC->count != 0)
return 0;
FREE(SC->contents);
SC->contents = MALLOC(newCapacity*sizeof(char *));
memset(SC->contents,0,sizeof(char *)*newCapacity);
SC->capacity = newCapacity;
return 1;
}

static void Apply(StringCollection *SC,int (*Applyfn)(char *,void *),void *arg){
int i;
for (i=0; i<SC->count;i++) {
Applyfn(SC->contents,arg);
}
}

static int *Map(StringCollection *SC,int (*Applyfn)(char *)){
int *result = MALLOC(SC->count*sizeof(int)),i;

if (result == NULL) return NULL;
for (i=0; i<SC->count;i++) {
result = Applyfn(SC->contents);
}
return result;
}

/* (e-mail address removed) (gerome) proposed calling DuplicateString. Good
suggestion */
static char *ReplaceAt(StringCollection *SC,int idx,char *newval){
char *r;
if (SC->Flags & SC_READONLY) return NULL;
if (idx < 0 || idx > SC->count) return NULL;
FREE(SC->contents[idx]);
r = DuplicateString(newval,"ReplaceAt");
if (r == NULL) return 0;
SC->contents[idx] = r;
return newval;
}

static bool Equal(StringCollection *SC1,StringCollection *SC2){
int i;
if (SC1->count != SC2->count) return 0;
if (SC1->count == 0) return 1;
for (i=0; i<SC1->count;i++) {
if (strcmp(SC1->contents,SC2->contents)) return 0;
}
return 1;
}

static StringCollection *Copy(StringCollection *SC){
int i;
StringCollection *result = newStringCollection(SC->count);

for (i=0; i<SC->count;i++) {
if (Add(result,SC->contents) <= 0) {
Finalize(result);
break;
}
}
return result;
}
 
B

Ben Bacarisse

jacob navia said:
if (!stricmp(SC->contents,str))


stricmp is not standard C. lcc-win32 (in conforming mode) should warn
that this function has no prototype in scope.
 
S

Seebs

jacob navia said:
if (!stricmp(SC->contents,str))

stricmp is not standard C. lcc-win32 (in conforming mode) should warn
that this function has no prototype in scope.

I'm not sure of this. Since str[a-z].* (regex notation, for those wondering
about the '.') are reserved by the standard, I don't think there's any
obligation for the implementation to diagnose the invocation of a call in
that namespace which it happens to define.

-s
 
B

Ben Bacarisse

Seebs said:
jacob navia said:
if (!stricmp(SC->contents,str))

stricmp is not standard C. lcc-win32 (in conforming mode) should warn
that this function has no prototype in scope.

I'm not sure of this. Since str[a-z].* (regex notation, for those wondering
about the '.') are reserved by the standard, I don't think there's any
obligation for the implementation to diagnose the invocation of a call in
that namespace which it happens to define.


I'm not sure either, anymore!

However, since a compiler can warn about anything it likes, I'd
suggest that it would be useful if lcc-win32 could be asked to issue a
warning in these cases. As a QOI issue, I really like to be told when
I am relying on non-standard functions.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,754
Messages
2,569,527
Members
44,998
Latest member
MarissaEub

Latest Threads

Top