Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > strcollection.c

Reply
Thread Tools

strcollection.c

 
 
jacob navia
Guest
Posts: n/a
 
      10-04-2009
/*------------------------------------------------------------------------
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_NOMEMOR Y);
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",CONTAINE R_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",CONTAINE R_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[i] != NULL) {
int r = Add(SC,data[i]);
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[i]);
SC->contents[i] = 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[i][0] && !strcmp(SC->contents[i],str)) return 1;
}
}
else {
for (i = 0; i<SC->count;i++) {
if (!stricmp(SC->contents[i],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[i] = DuplicateString(SC->contents[i],"Copy");
}
result[i] = 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[i],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[i]);
}
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[i],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[i] = Applyfn(SC->contents[i]);
}
return result;
}

/* http://www.velocityreviews.com/forums/(E-Mail 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[i],SC2->contents[i])) 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[i]) <= 0) {
Finalize(result);
break;
}
}
return result;
}
 
Reply With Quote
 
 
 
 
Ben Bacarisse
Guest
Posts: n/a
 
      10-05-2009
jacob navia <(E-Mail Removed)> writes:
<snip>
> if (!stricmp(SC->contents[i],str))


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

--
Ben.
 
Reply With Quote
 
 
 
 
Seebs
Guest
Posts: n/a
 
      10-05-2009
On 2009-10-05, Ben Bacarisse <(E-Mail Removed)> wrote:
> jacob navia <(E-Mail Removed)> writes:
><snip>
>> if (!stricmp(SC->contents[i],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
--
Copyright 2009, all wrongs reversed. Peter Seebach / (E-Mail Removed)
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      10-05-2009
Seebs <(E-Mail Removed)> writes:

> On 2009-10-05, Ben Bacarisse <(E-Mail Removed)> wrote:
>> jacob navia <(E-Mail Removed)> writes:
>><snip>
>>> if (!stricmp(SC->contents[i],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.

--
Ben.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off




Advertisments