/* Clist.h */ /* 2016-10-07 */
/*
BEFORE loading ... you MUST FIRST typedef (struct) Node and pNode
i.e. typedef a struct/node/element/record as Node and typedef Node* pNode;
... and ... define clearNode( pNode p ); ... see example at end
*/
#ifndef dwClist_H
#define dwClist_H
/* #include <stdlib.h> // re. realloc */
/* #include <string.h> // re. memcopy */
typedef struct myClist
{
pNode start;
pNode end;
int size;
int isSorted;
} Clist;
/* with these, an address is passed, so NO copy made and/or
original updated */
void initClist( Clist* ); /* set start&end to NULL, size to 0, isSorted to 1 */
void push_frontClist( Clist*, pNode );
void push_backClist( Clist*, pNode );
void clearClist( Clist* );
/* void showClist( Clist* ); */
void initClist( Clist* list )
{
list->start = list->end = NULL;
list->size = 0;
list->isSorted = 1;
}
void push_frontClist( Clist* list, pNode d )
{
pNode p = (pNode) malloc( sizeof(Node) );
if( p == NULL )
{
clearClist( list );
myAssert( 0, "Error: malloc failed ...." );
}
/* now add in ALL new dat ... (assuming 'next pointer' is last in struct) */
memcpy( p, d, sizeof(Node)-sizeof(pNode) ); /* -sizeof(any_pointer) is ok */
/* and set pointers to next ... and start ...*/
p->next = list->start;
list->start = p;
++ list->size;
if( list->size > 1 ) list->isSorted = 0;
else list->end = list->start;
}
void push_backClist( Clist* list, pNode d )
{
pNode p = (pNode) malloc( sizeof(Node) );
if( p == NULL )
{
clearClist( list );
myAssert( 0, "Error: malloc failed ..." );
}
/* now add in ALL new dat ... (assuming next pointer is last of dat) */
memcpy( p, d, sizeof(Node)-sizeof(pNode) ); /* -sizeof(any_pointer) is ok */
/* and set pointers to next ... and start ...*/
p->next = NULL;
++ list->size;
if( list->size > 1 )
{
list->end->next = p;
list->end = p;
list->isSorted = 0;
}
else
list->start = list->end = p;
}
void clearClist( Clist* list )
{
/* printf( "\nFreeing list->size of %d ... \n", list->size ); */
if( list->size > 0 )
{
pNode cur = list->start;
for( ; cur != NULL; cur = list->start )
{
list->start = cur->next;
clearNode( cur );
free( cur );
}
initClist( list );
}
}
/*
void showClist( Clist* list )
{
if( list->size )
{
pNode p = list->start;
for( ; p != NULL; p = p->next )
showNode( p );
printf( "Node size = %d\n", list->size );
}
else puts( "The list is empty ... " );
}
*/
#endif
#if 0 /* *************************************************************** */
/* before we can include the Clist.h file below, we first need these ... */
#include <stdlib.h> /* re. alloc, exit */
#include <string.h> /* re. memcpy */
typedef struct ClistOfInt
{
int val;
struct ClistOfInt* next;
} Node ; /* i.e. ... a node/element/record in the list ... */
typedef Node* pNode;
void clearNode( pNode p )
{
/* no dynamic Cstrings, etc... to free here ... */
}
/*
void showNode( pNode p )
{
printf( "%d ", p->val );
}
*/
#ifndef dwMYASSERT
#define dwMYASSERT
void myAssert( int (condition), const char text[] )
{
if( !condition )
{
fprintf(stderr, "%s\n", text );
fputs( "Press 'Enter' to exit program ... ", stderr );
getchar();
exit(1);
}
}
#endif
/* Ok ... NOW can include ... */
#include "Clist.h"
/* needs stdlib.h, string.h and myAssert & all included above */
#endif /* ************************************************************* */
/* ClistOfInt.h */ /* this version: 2016-10-07 */
/*
this version with added isortClist and insert_sortedClist (still has msort)
also added isSorted, unique, isUnique, sumClist, findClist, eraseClist
*/
#ifndef dwClistOfInt_H
#define dwClistOfInt_H
/* before we can include the Clist.h file below, we first need these ... */
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* re. memcpy */
#ifndef myType
#define myType int
#endif
typedef struct ClistOfInt
{
myType val;
struct ClistOfInt* next;
} Node ; /* i.e. ... a node/element/record in the list ... */
typedef Node* pNode;
void clearNode( pNode p )
{
/* no dynamic Cstrings, etc... to free here ... */
p = p; /* to keer warning message surpressed */
}
/*
void showNode( pNode p )
{
printf( "%d ", p->val );
}
*/
#ifndef dwMYASSERT
#define dwMYASSERT
void myAssert( int condition, const char text[] )
{
if( !condition )
{
fprintf(stderr, "%s\n", text );
fputs( "Press 'Enter' to exit program ... ", stderr );
getchar();
exit(1);
}
}
#endif
/* Ok ... NOW can include ... */
#include "Clist.h"
/* needs stdio.h, stdlib.h, string.h and myAssert & all included above */
/* and now can add these functions to ClistOfInt...*/
void msortClist( Clist* );
void mergesort( Clist* );
pNode mergeClist( Clist*, Clist* );
void update_end( Clist* );
void insert_sortedClist( Clist*, pNode );
void isortClist( Clist* );
int isSortedClist( Clist* );
void uniqueClist( Clist* );
int isUniqueClist( Clist* );
myType sumClist( Clist* );
pNode findClist( Clist*, myType ); /* returns pointer to list with int value, or NULL */
void eraseClist( Clist* cl, pNode p );
/* a recursive mergesort ... */
void mergesort(Clist* list)
{
pNode cur = list->start;
Clist a, b;
/* base case is a Clist of length 0 or 1 ... */
if ((cur == NULL) || (cur->next == NULL)) return;
/* split Clist into 'a' and 'b' sublists ... */
a.start = cur;
b.start = cur->next;
while((b.start != NULL) && (b.start->next != NULL))
{
cur = cur->next;
b.start = b.start->next->next;
}
b.start = cur->next;
cur->next = NULL; /* Clist divided into 2 roughly equal parts now ... */
/* recursively sort the sublists ... */
mergesort(&a);
mergesort(&b);
/* merge the two sorted Clists together ... */
list->start = mergeClist(&a, &b);
}
/* merge two sorted Clists with heads 'a' and 'b' ... in sorted order */
pNode mergeClist(Clist* a, Clist* b )
{
pNode sorted, new_merged_head;
if( a->start == NULL ) return b->start;
if( b->start == NULL ) return a->start;
if( a->start->val - b->start->val <= 0 )
{
sorted = a->start;
a->start = a->start->next;
}
else
{
sorted = b->start;
b->start = b->start->next;
}
new_merged_head = sorted;
/* now ... */
while( a->start != NULL && b->start != NULL )
{
if( a->start->val - b->start->val <= 0 )
{
sorted->next = a->start;
sorted = a->start;
a->start = a->start->next;
}
else
{
sorted->next = b->start;
sorted = b->start;
b->start = b->start->next;
}
}
/* and finally ... */
if( a->start != NULL )
sorted->next = a->start;
else if( b->start != NULL )
sorted->next = b->start;
return new_merged_head;
}
void update_end( Clist* list ) /* after sort */
{
if( list->size > 1 )
{
pNode cur;
for( cur = list->start; cur->next != NULL; cur = cur->next ) ;
list->end = cur;
list->end->next = NULL;
}
}
void msortClist( Clist* c )
{
mergesort( c );
update_end( c );
c->isSorted = 1;
}
int isSortedClist( Clist* c )
{
pNode p = c->start;
for( ; p != NULL && p->next != NULL; p = p->next )
if( p->next->val < p->val ) return 0;
return 1;
}
void uniqueClist( Clist* c )
{
pNode p;
if( !c->isSorted ) msortClist( c );
p = c->start;
while( p->next != NULL )
{
if( p->val == p->next->val )
{
pNode tmp = p->next;
p->next = p->next->next;
free( tmp );
-- c->size;
}
else p = p->next;
}
update_end( c ) ; /* update end ... */
}
int isUniqueClist( Clist* cl )
{
pNode p = cl->start;
if( cl->size < 2 ) return 1;
if( !cl->isSorted ) msortClist( cl );
for( ; p->next != NULL; p = p->next )
{
if( p->val == p->next->val ) return 0;
}
/* else */
return 1;
}
myType sumClist( Clist* cl )
{
myType sum = 0;
pNode p;
for( p = cl->start; p != NULL; p = p->next ) sum += p->val;
return sum;
}
pNode findClist( Clist* cl, myType value )
{
pNode p;
for( p = cl->start; p != NULL; p = p->next )
if( p->val == value ) return p;
/* else if reach here ... */
return NULL;
}
void eraseClist( Clist* cl, pNode p )
{
if( cl->size )
{
pNode cur = cl->start;
pNode prev = NULL;
for( ; cur!= NULL && cur != p; cur = cur->next ) /* advance to p or end */
prev = cur;
if( cur == NULL ) { puts( "ERROR! pNode NOT found in Clist." ); return; }
/* else ... */
if( prev != NULL ) prev->next = cur->next;
if( cur == cl->start ) cl->start = cur->next;
if( cur == cl->end ) cl->end = prev;
free( cur );
-- cl->size; /* ...and update size */
}
else puts( "Clist is empty ..." );
}
/* pass in the address of the Clist and the new Node to insert ... */
void insert_sortedClist( Clist* list, pNode n )
{
pNode head;
if( !list->isSorted ) msortClist( list );
head = list->start;
/* firstly, we handle most common case where 'n' is NOT the first Node */
if( head != NULL && n->val >= head->val ) /* NEED >= */
{
/* so search the linked list for the right location */
pNode cur = head;
while( cur->next != NULL && cur->next->val <= n->val )
{
cur = cur->next;
}
if( cur == list->end ) list->end = n;
n->next = cur->next;
cur->next = n;
/* list->start = head; // unchanged */
++ list->size;
}
else /* if we reach here, this IS the first node ... */
{
n->next = head; /* so set this node in first position */
list->start = n;
++ list->size;
if( list->size == 1 ) list->end = n;
}
}
void isortClist( Clist* list )
{
pNode cur,
nextNode;
Clist nClist;
initClist( &nClist );
for( cur = list->start; cur != NULL; cur = nextNode )
{
nextNode = cur->next; /* get copy here before next is changed below ...*/
insert_sortedClist( &nClist, cur ); /* 'cur' already is a Node pointer */
}
/* now ... update old list with new front and back ... */
list->start = nClist.start;
list->end = nClist.end;
list->isSorted = 1;
/* size hasn't changed ... */
}
#endif
/* ClistOfString.h */ /* 2016-10-07 */
/* version @ 2015-12-17 has added: char* pop_frontClist( Clist* cl ); */
/*
this version with added isortClist and insert_sortedClist (still has msort)
isSorted, unique, isUnique, joinClist, showClist, findClist, eraseClist
*/
#ifndef dwClistOfString_H
#define dwClistOfString_H
/* using readLine here instead of gets and fgets ... readLine.h also includes */
#include "readLine.h" /* ... stdio.h, stdlib.h, string.h, myAssert, newCopy */
#ifndef sort_offset
#define sort_offset 0
#endif
typedef struct ClistOfString
{
char* str; /* since CStrings are '\0' terminated ... can get strlen */
struct ClistOfString* next;
} Node ; /* i.e. ... a node/element/record in the list ... */
typedef Node* pNode;
void clearNode( pNode p )
{
free( p->str );
}
/* Ok ... NOW can include ... */
#include "Clist.h"
/* needs stdlib.h, string.h and myAssert & all included above */
void showNode( pNode p )
{
printf( "%s ", p->str );
}
/* and these ...*/
void msortClist( Clist* );
void mergesortClist( Clist* );
pNode mergeClist( Clist*, Clist* );
void update_end( Clist* );
void insert_sortedClist( Clist*, pNode );
void isortClist( Clist* );
int isSortedClist( Clist* );
void uniqueClist( Clist* );
int isUniqueClist( Clist* );
char* joinClist( Clist*, const char* );
void showClist( const Clist* );
pNode findClist( Clist*, const char* findStr );
void eraseClist( Clist*, pNode );
char* pop_frontClist( Clist* cl );
/* a recursive mergesortClist ... */
void mergesortClist(Clist* list)
{
pNode cur = list->start;
Clist a, b;
/* base case is a Clist of length 0 or 1 ... */
if ((cur == NULL) || (cur->next == NULL)) return;
/* split Clist into 'a' and 'b' sublists ... */
a.start = cur;
b.start = cur->next;
while((b.start != NULL) && (b.start->next != NULL))
{
cur = cur->next;
b.start = b.start->next->next;
}
b.start = cur->next;
cur->next = NULL; /* Clist divided into 2 roughly equal parts now ... */
/* recursively sort the sublists ... */
mergesortClist(&a);
mergesortClist(&b);
/* mergeClist the two sorted Clists together ... */
list->start = mergeClist(&a, &b);
}
/* mergeClist two sorted Clists with heads 'a' and 'b' ... in sorted order */
pNode mergeClist(Clist* a, Clist* b )
{
pNode sorted, new_merged_head;
if( a->start == NULL ) return b->start;
if( b->start == NULL ) return a->start;
if( strcmp(a->start->str + sort_offset, b->start->str + sort_offset) <= 0 )
{
sorted = a->start;
a->start = a->start->next;
}
else
{
sorted = b->start;
b->start = b->start->next;
}
new_merged_head = sorted;
/* now ... */
while( a->start != NULL && b->start != NULL )
{
if( strcmp(a->start->str + sort_offset, b->start->str + sort_offset) <= 0 )
{
sorted->next = a->start;
sorted = a->start;
a->start = a->start->next;
}
else
{
sorted->next = b->start;
sorted = b->start;
b->start = b->start->next;
}
}
/* and finally ... */
if( a->start != NULL )
sorted->next = a->start;
else if( b->start != NULL )
sorted->next = b->start;
return new_merged_head;
}
void update_end( Clist* list ) /* after sort */
{
if( list->size > 1 )
{
pNode cur;
for( cur = list->start; cur->next != NULL; cur = cur->next ) ;
list->end = cur;
list->end->next = NULL;
}
}
void msortClist( Clist* clst )
{
mergesortClist( clst );
update_end( clst );
clst->isSorted = 1;
}
int isSortedClist( Clist* c )
{
pNode p = c->start;
for( ; p != NULL && p->next != NULL; p = p->next )
if( strcmp(p->next->str, p->str) < 0 ) return 0;
return 1;
}
void uniqueClist( Clist* c )
{
pNode p;
int oldSize = c->size;
if( !c->isSorted ) msortClist( c );
p = c->start;
while( p->next != NULL )
{
if( strcmp(p->str + sort_offset, p->next->str + sort_offset) == 0 )
{
pNode tmp = p->next;
p->next = p->next->next;
clearNode( tmp ); /* needed here for types like dynamic Cstrings, etc */
free( tmp );
-- c->size;
}
else p = p->next;
}
if( c->size < oldSize ) update_end( c ) ; /* update end ... */
}
int isUniqueClist( Clist* cl )
{
pNode p = cl->start;
if( cl->size < 2 ) return 1;
if( !cl->isSorted ) msortClist( cl );
for( ; p->next != NULL; p = p->next )
{
if( strcmp( p->str, p->next->str ) == 0 ) return 0;
}
/* else */
return 1;
}
char* joinClist( Clist* cl, const char* s )
{
char* concatStr;
int sumsize = 0;
int add = strlen( s );
pNode p;
for( p = cl->start; p != NULL; p = p->next ) sumsize += strlen(p->str) + add;
concatStr = (char*) malloc( sumsize-add+1 );
myAssert( (concatStr != NULL), "Error, malloc failed to allocate memory for concatStr" );
concatStr[0] = 0;
for( p = cl->start; p != NULL; p = p->next )
{
strcat( concatStr, p->str );
if( p->next != NULL ) strcat( concatStr, s );
}
return concatStr;
}
void showClist( const Clist* cl )
{
pNode p = cl->start;
for( ; p != NULL; p = p->next ) showNode( p ); /*printf( "%s ", p->str ); */
}
/* returns pointer if present, else returns NULL */
pNode findClist( Clist* cl, const char* findStr )
{
pNode p;
for( p = cl->start; p != NULL; p = p->next )
if( strcmp(p->str, findStr) == 0 ) return p;
/* else if reach here ... */
return NULL;
}
void eraseClist( Clist* cl, pNode p ) /* if p valid, erase element there */
{
pNode prev = NULL, cur = cl->start;
for( ; cur != NULL && cur != p; cur = cur->next ) prev = cur;
if( cur == NULL )
{ puts( "\neraseClist ERROR! Pointer NOT found ..."); return; }
if( prev != NULL ) prev->next = cur->next; /* case of NOT FIRST element*/
else cl->start = cl->start->next; /* case of IS FIRST element*/
if( cur == cl->end ) cl->end = prev; /* case of IS LAST element*/
clearNode( cur ); /* needed here for types like dynamic C strings, etc */
free( cur ); /* free memory for dynamic Node ... */
/* now update size and return (by reference, since address passed in) */
-- cl->size;
}
char* pop_frontClist( Clist* cl )
{
if( cl->size )
{
pNode cur = cl->start;
char* str = cur->str ;
cl->start = cur->next;
/* free( cur->str ); */
free( cur ); /* free memory for dynamic Node ... */
-- cl->size; /* now update size ... */
if( !cl->size ) cl->end = NULL; /* update end if Clist is empty */
return str; /* and return (by reference, since address passed in) */
}
return newCopy( "" );
}
/* pass in the address of the Clist and the new Node to insert ... */
void insert_sortedClist( Clist* list, pNode n )
{
pNode head;
if( !list->isSorted ) msortClist( list );
head = list->start;
/* firstly, we handle most common case where 'n' is NOT the first Node */
if( head != NULL && strcmp( n->str, head->str ) >= 0 ) /* NEED >= */
{
/* so search the linked list for the right location */
pNode cur = head;
while( cur->next != NULL && strcmp( cur->next->str, n->str ) <= 0 )
{
cur = cur->next;
}
if( cur == list->end ) list->end = n;
n->next = cur->next;
cur->next = n;
/* list->start = head; // unchanged */
++ list->size;
}
else /* if we reach here, this IS the first node ... */
{
n->next = head; /* so set this node in first position */
list->start = n;
++ list->size;
if( list->size == 1 ) list->end = n;
}
}
void isortClist( Clist* list )
{
pNode cur,
nextNode;
Clist nClist;
initClist( &nClist );
for( cur = list->start; cur != NULL; cur = nextNode )
{
nextNode = cur->next; /* get copy here before next is changed below ...*/
insert_sortedClist( &nClist, cur ); /* 'cur' already is a Node pointer */
}
/* now ... update old list with new front and back ... */
list->start = nClist.start;
list->end = nClist.end;
list->isSorted = 1;
/* size hasn't changed ... */
}
#endif /* end of #ifndef dwClistOfString_H */
/* push_pop_words.c */ /* 2016-1o-13 */
/* a demo of using a ClistOfString as a 'stack' ... */
#include "ClistOfString.h" /* includes files: "readLine.h" and "Clist.h" */
#define pushClist push_frontClist
#define popClist pop_frontClist
int isEmptyClist( const Clist* cl )
{
return cl->size == 0;
}
/* print from front to back ... */
void printClist( const Clist* cl )
{
pNode cur = cl->start;
for( ; cur != NULL; cur = cur->next )
printf( "%s ", cur->str );
}
int main()
{
/* Get some test data to work with ... */
char* words[] = { "a", "big", "fat", "cat", "was",
"black", "with", "white", "patches", "all", "over" };
const int size = sizeof words / sizeof *words;
int i;
Clist stk, stk2;
Node lst;
initClist( &stk ); /* MUST inital to work OK ... */
initClist( &stk2 );
puts( "Printing the array ... " );
for( i = 0; i < size; ++ i )
{
/* lst.str = newCopy(words[i]);
if you use a new copy in dynamic memory ...
then free that memory when done with it here. */
lst.str = words[i];
pushClist( &stk, &lst );
printf( "%s ", words[i] );
}
puts( "\n\nPrinting the Clist after array was 'pushed' onto it... " );
printClist( &stk );
puts( "\n\nPrinting the stack while popping elements ... " );
while( !isEmptyClist( &stk ) )
{
/* below we pass the pointer to the (perhaps dynamic) C string in the Node ...
BUT we ...
free the memory that held each dynamic Node. */
char* str = popClist( &stk );
printf( "%s ", str );
/* free( str ); free if dynamic Cstring & if done with it */
lst.str = str;
pushClist( &stk2, &lst ); /* push_front onto a 2nd list */
}
puts( "\n\nPrinting the 2nd stack while popping elements ... " );
while( stk2.size ) /* OK ... here we see the recersed order ... */
{
char* str = popClist( &stk2 );
printf( "%s ", str );
}
puts( "\n" );
do
{
printf( "Enter a 'word' to 'push' (onto the 'stack'): " );
fflush( stdout );
lst.str = readLine( stdin );
pushClist( &stk, &lst );
}
while( more() );
while( !isEmptyClist( &stk ) )
{
lst.str = popClist( &stk );
printf( "%s ", lst.str );
pushClist( &stk2, &lst );
}
putchar( '\n' );
while( !isEmptyClist( &stk2 ) )
{
char* str = popClist( &stk2 );
printf( "%s ", str );
free( str ); /* free each dynamic Cstring when done with it */
}
fputs( "\nPress 'Enter' to continue/exit ... ", stdout );
fflush ( stdout );
getchar();
return 0;
}
/* Clist_func's.h */ /* 2016-10-07 */
/*
this version using function pointers ... has ...
msortClist, isortClist, insert_sortedClist, isSortedClist,
uniqueClist, isUniqueClist, findClist, eraseClist (i.e. erase node)
*/
#ifndef dwClist_funcs_H
#define dwClist_funcs_H
/* function protoypes ...*/
void msortClist( Clist*, int (*myCmp) (const pNode, const pNode) );
void mergesortClist( Clist*, int (*myCmp) (const pNode, const pNode) );
pNode mergeClists( Clist*, Clist*, int (*myCmp) (const pNode, const pNode) );
void update_end( Clist* );
void insert_sortedClist( Clist*, pNode, int (*myCmp) (const pNode, const pNode) );
void isortClist( Clist*, int (*myCmp) (const pNode , const pNode) );
int isSortedClist( Clist*, int (*myCmp) (const pNode, const pNode) );
void uniqueClist( Clist*, int (*myCmp) (const pNode, const pNode) );
int isUniqueClist( Clist*, int (*myCmp) (const pNode a, const pNode b) );
pNode findClist( Clist*, const pNode, int (*myCmp) (const pNode, const pNode) );
void eraseClist( Clist*, pNode );
/* function definitions ...*/
/* a recursive mergesort ... */
void mergesortClist(Clist* list, int (*myCmp) (const pNode r1, const pNode r2) )
{
pNode cur = list->start;
Clist a, b;
/* base case is a Clist of length 0 or 1 ... */
if ((cur == NULL) || (cur->next == NULL)) return;
/* split Clist into 'a' and 'b' sublists ... */
a.start = cur;
b.start = cur->next;
while((b.start != NULL) && (b.start->next != NULL))
{
cur = cur->next;
b.start = b.start->next->next;
}
b.start = cur->next;
cur->next = NULL; /* Clist divided into 2 roughly equal parts now ... */
/* recursively sort the sublists ... */
mergesortClist(&a, myCmp);
mergesortClist(&b, myCmp);
/* merge the two sorted Clists together ... */
list->start = mergeClists(&a, &b, myCmp);
}
/* merge two sorted Clists with heads 'a' and 'b' ... in sorted order */
pNode mergeClists(Clist* a, Clist* b, int (*myCmp) (const pNode r1, const pNode r2) )
{
pNode sorted, new_merged_head;
if( a->start == NULL ) return b->start;
if( b->start == NULL ) return a->start;
if( myCmp(a->start, b->start) <= 0 )
{
sorted = a->start;
a->start = a->start->next;
}
else
{
sorted = b->start;
b->start = b->start->next;
}
new_merged_head = sorted;
/* now ... */
while( a->start != NULL && b->start != NULL )
{
if( myCmp(a->start, b->start) <= 0 )
{
sorted->next = a->start;
sorted = a->start;
a->start = a->start->next;
}
else
{
sorted->next = b->start;
sorted = b->start;
b->start = b->start->next;
}
}
/* and finally ... */
if( a->start != NULL )
sorted->next = a->start;
else if( b->start != NULL )
sorted->next = b->start;
return new_merged_head;
}
void update_end( Clist* list ) /* after sort */
{
if( list->size > 1 )
{
pNode cur;
for( cur = list->start; cur->next != NULL; cur = cur->next ) ;
list->end = cur;
list->end->next = NULL;
}
}
void msortClist( Clist* clst, int (*myCmp) (const pNode r1, const pNode r2) )
{
mergesortClist( clst, myCmp );
update_end( clst );
clst->isSorted = 1;
}
int isSortedClist( Clist* c, int (*myCmp) (const pNode r1, const pNode r2) )
{
pNode p = c->start;
for( ; p != NULL && p->next != NULL; p = p->next )
if( myCmp(p->next, p) < 0 ) return 0;
return 1;
}
void uniqueClist( Clist* c, int (*myCmp) (const pNode r1, const pNode r2) )
{
int oldSize = c->size;
pNode p;
if( !isSortedClist(c, myCmp) ) msortClist( c, myCmp );
p = c->start;
while( p->next != NULL )
{
if( myCmp(p, p->next) == 0 )
{
pNode tmp = p->next;
p->next = p->next->next;
clearNode( tmp ); /* needed here for types like dynamic Cstrings, etc */
free( tmp );
-- c->size;
}
else p = p->next;
}
if( c->size < oldSize ) update_end( c ) ; /* update end ... */
}
int isUniqueClist( Clist* cl, int (*myCmp) (const pNode a, const pNode b) )
{
pNode p = cl->start;
if( cl->size < 2 ) return 1;
if( !cl->isSorted ) msortClist( cl, myCmp );
for( ; p->next != NULL; p = p->next )
{
if( myCmp( p, p->next ) == 0 ) return 0;
}
/* else */
return 1;
}
/* returns pointer if present, else returns NULL */
pNode findClist( Clist* cl, const pNode pr, int (*myCmp) (const pNode r1, const pNode r2) )
{
pNode p;
for( p = cl->start; p != NULL; p = p->next )
if( myCmp(p, pr) == 0 ) return p;
/* else if reach here ... */
return NULL;
}
void eraseClist( Clist* cl, pNode p ) /* if p valid, erase element there */
{
pNode prev = NULL, cur = cl->start;
for( ; cur != NULL && cur != p; cur = cur->next ) prev = cur;
if( cur == NULL )
{ puts( "\neraseClist ERROR! Pointer NOT found ..."); return; }
if( prev != NULL ) prev->next = cur->next; /* case of NOT FIRST element*/
else cl->start = cl->start->next; /* case of IS FIRST element*/
if( cur == cl->end ) cl->end = prev; /* case of IS LAST element*/
clearNode( cur ); /* needed here for types like dynamic C strings, etc */
free( cur ); /* free memory for dynamic Node ... */
/* now update size and return (by reference, since address passed in) */
-- cl->size;
}
/* pass in the address of the Clist and the new Node to insert ... */
void insert_sortedClist( Clist* list, pNode n, int (*myCmp) (const pNode r1, const pNode r2) )
{
pNode head;
if( !isSortedClist( list, myCmp )) msortClist( list, myCmp );
head = list->start;
/* firstly, we handle most common case where 'n' is NOT the first Node */
if( head != NULL && myCmp( n, head ) >= 0 ) /* NEED >= */
{
/* so search the linked list for the right location */
pNode cur = head;
while( cur->next != NULL && myCmp( cur->next, n ) <= 0 )
{
cur = cur->next;
}
if( cur == list->end ) list->end = n;
/* For A->B to become A->N->B */
n->next = cur->next; /* N->B */
cur->next = n; /* A->N */
}
else /* if we reach here, this IS the first node ... */
{
n->next = head; /* so set this node in first position */
list->start = n;
if( ! list->size ) list->end = n;
}
++ list->size;
}
void isortClist( Clist* list, int (*myCmp) (const pNode r1, const pNode r2) )
{
pNode cur,
nextNode;
Clist nClist;
initClist( &nClist );
for( cur = list->start; cur != NULL; cur = nextNode )
{
nextNode = cur->next; /* get copy here before next is changed below ...*/
insert_sortedClist( &nClist, cur, myCmp ); /* 'cur' already is a Node pointer */
}
/* now ... update old list with new front and back ... */
list->start = nClist.start;
list->end = nClist.end;
list->isSorted = 1;
/* size hasn't changed ... */
}
#endif
/* test_ClistOfString2.c */ /* 2016-10-09 */
#include "ClistOfString2.h" /* includes readLine2.h and includes Clist.h*/
#include "readWord2.h"
#define START_WORD_SIZE 32
void myShowClist( const Clist* cl )
{
pNode p;
for( p = cl->start ; p != NULL ; p = p->next )
printf( "'%s' with size %u\n", p->str, p->size );
}
int main()
{
unsigned textLen = 0;
char* text;
const char delimiters[] = " \t\n";
char lastCharRead;
Node item;
Clist myLines, words;
initClist( &myLines ); /* MUST initial Clist object for push_back, etc... to work ok ... */
initClist( &words );
do
{
fputs( "Enter a line of text to add to Clist: ", stdout ); fflush( stdout );
item.str = readLine2( stdin, &item.size );
push_backClist( &myLines, &item );
splitClist( &words, item.str, " \n" );
}
while( more() );
fputs( "You entered lines: \n", stdout ); fflush( stdout );
myShowClist( &myLines );
clearClist( &myLines );
text = joinClist( &words, " ", &textLen );
myShowClist( &words );
clearClist( &words );
printf( "\ntext is '%s' with len = %d\n", text, textLen );
free( text );
do
{
fputs( "Enter a line of words to add to Clist: ", stdout ); fflush( stdout );
while( (item.str = readWord2( stdin, START_WORD_SIZE, delimiters, &lastCharRead, &item.size)) )
{
push_backClist( &myLines, &item );
if( lastCharRead == '\n' ) break;
}
fputs( "You entered words: \n", stdout ); fflush( stdout );
myShowClist( &myLines );
clearClist( &myLines );
}
while( more() );
takeInChar( "Press 'Enter' to continue/exit ... " );
return 0;
}
/* ClistOfString2.h */ /* 2016-10-09 */
/*
this version with added isortClist and insert_sortedClist (still has msort)
isSorted, unique, isUnique, joinClist, showClist, findClist, eraseClist
*/
#ifndef dwClistOfString_H
#define dwClistOfString_H
#ifndef sort_offset
#define sort_offset 0
#endif
/* using readLine here instead of gets and fgets ... readLine.h also includes */
#include "readLine2.h" /* ... stdio.h, stdlib.h, string.h, myAssert, newCopy */
typedef struct ClistOfString
{
char* str; /* since CStrings are '\0' terminated ... can get strlen */
unsigned size;
struct ClistOfString* next;
} Node ; /* i.e. ... a node/element/record in the list ... */
typedef Node* pNode;
void clearNode( pNode p )
{
free( p->str );
}
/* Ok ... NOW can include ... */
#include "Clist.h"
/* needs stdlib.h, string.h and myAssert & all included above */
void showNode( pNode p )
{
printf( "%s ", p->str );
}
/* and these ...*/
void msortClist( Clist* );
void mergesortClist( Clist* );
pNode mergeClist( Clist*, Clist* );
void update_end( Clist* );
void insert_sortedClist( Clist*, pNode );
void isortClist( Clist* );
int isSortedClist( const Clist* );
void uniqueClist( Clist* );
int isUniqueClist( Clist* );
void splitClist( Clist*, const char* strIn, const char* delimits );
char* joinClist( Clist* cl, const char* sep, unsigned* len );
void showClist( const Clist* );
pNode findClist( const Clist*, const char* findStr );
void eraseClist( Clist*, pNode );
/* a recursive mergesort ... */
void mergesortClist(Clist* list)
{
pNode cur = list->start;
Clist a, b;
/* base case is a Clist of length 0 or 1 ... */
if ((cur == NULL) || (cur->next == NULL)) return;
/* split Clist into 'a' and 'b' sublists ... */
a.start = cur;
b.start = cur->next;
while((b.start != NULL) && (b.start->next != NULL))
{
cur = cur->next;
b.start = b.start->next->next;
}
b.start = cur->next;
cur->next = NULL; /* Clist divided into 2 roughly equal parts now ... */
/* recursively sort the sublists ... */
mergesortClist(&a);
mergesortClist(&b);
/* merge the two sorted Clists together ... */
list->start = mergeClist(&a, &b);
}
/* merge two sorted Clists with heads 'a' and 'b' ... in sorted order */
pNode mergeClist(Clist* a, Clist* b )
{
pNode sorted, new_merged_head;
if( a->start == NULL ) return b->start;
if( b->start == NULL ) return a->start;
if( strcmp(a->start->str + sort_offset, b->start->str + sort_offset) <= 0 )
{
sorted = a->start;
a->start = a->start->next;
}
else
{
sorted = b->start;
b->start = b->start->next;
}
new_merged_head = sorted;
/* now ... */
while( a->start != NULL && b->start != NULL )
{
if( strcmp(a->start->str + sort_offset, b->start->str + sort_offset) <= 0 )
{
sorted->next = a->start;
sorted = a->start;
a->start = a->start->next;
}
else
{
sorted->next = b->start;
sorted = b->start;
b->start = b->start->next;
}
}
/* and finally ... */
if( a->start != NULL )
sorted->next = a->start;
else if( b->start != NULL )
sorted->next = b->start;
return new_merged_head;
}
void update_end( Clist* list ) /* after sort */
{
if( list->size > 1 )
{
pNode cur;
for( cur = list->start; cur->next != NULL; cur = cur->next ) ;
list->end = cur;
list->end->next = NULL;
}
}
void msortClist( Clist* clst )
{
mergesortClist( clst );
update_end( clst );
clst->isSorted = 1;
}
int isSortedClist( const Clist* c )
{
pNode p = c->start;
for( ; p != NULL && p->next != NULL; p = p->next )
if( strcmp(p->next->str, p->str) < 0 ) return 0;
return 1;
}
void uniqueClist( Clist* c )
{
pNode p;
if( !c->isSorted ) msortClist( c );
p = c->start;
while( p->next != NULL )
{
if( strcmp(p->str + sort_offset, p->next->str + sort_offset) == 0 )
{
pNode tmp = p->next;
p->next = p->next->next;
clearNode( tmp ); /* needed here for types like dynamic Cstrings, etc */
free( tmp );
-- c->size;
}
else p = p->next;
}
update_end( c ) ; /* update end ... */
}
int isUniqueClist( Clist* cl )
{
pNode p = cl->start;
if( cl->size < 2 ) return 1;
if( !cl->isSorted ) msortClist( cl );
for( ; p->next != NULL; p = p->next )
{
if( strcmp( p->str, p->next->str ) == 0 ) return 0;
}
/* else */
return 1;
}
void splitClist( Clist* lst, const char* strIn, const char* delimits )
{
const char *p2, *p1 = strIn;
Node ml; /* ml is really a ... node/element/record in a List ... */
for( ; ; ) /* loop forever ... until break */
{
while( *p1 != 0 && strchr(delimits, *p1) ) ++p1;
if( *p1 == 0 ) break; /* i.e. if empty or all delimits */
p2 = p1+1;
while( *p2 != 0 && !strchr(delimits, *p2) ) ++p2;
ml.str = newsubstr( strIn, p1-strIn, p2-p1 ); /* new copy in new memory in ml.str */
ml.size = p2-p1;
push_backClist( lst, &ml ); /* default is push_backClist */
p1 = p2;
}
}
char* joinClist( Clist* cl, const char* sep, unsigned* len )
{
char* concatStr;
unsigned sumsize = 0;
unsigned add = strlen( sep );
pNode p;
for( p = cl->start; p != NULL; p = p->next ) sumsize += (p->size) + add;
*len = sumsize-add;
concatStr = (char*) malloc( *len+1 );
myAssert( (concatStr != NULL), "Error, malloc failed to allocate memory for concatStr" );
concatStr[0] = 0;
for( p = cl->start; p != NULL; p = p->next )
{
strcat( concatStr, p->str );
if( p->next != NULL ) strcat( concatStr, sep );
}
return concatStr;
}
void showClist( const Clist* cl )
{
pNode p = cl->start;
for( ; p != NULL; p = p->next ) showNode( p ); /*printf( "%s ", p->str ); */
}
/* returns pointer if present, else returns NULL */
pNode findClist( const Clist* cl, const char* findStr )
{
pNode p;
for( p = cl->start; p != NULL; p = p->next )
if( strcmp(p->str, findStr) == 0 ) return p;
/* else if reach here ... */
return NULL;
}
void eraseClist( Clist* cl, pNode p ) /* if p valid, erase element there */
{
pNode prev = NULL, cur = cl->start;
for( ; cur != NULL && cur != p; cur = cur->next ) prev = cur;
if( cur == NULL )
{ puts( "\neraseClist ERROR! Pointer NOT found ..."); return; }
if( prev != NULL ) prev->next = cur->next; /* case of NOT FIRST element*/
else cl->start = cl->start->next; /* case of IS FIRST element*/
if( cur == cl->end ) cl->end = prev; /* case of IS LAST element*/
clearNode( cur ); /* needed here for types like dynamic C strings, etc */
free( cur ); /* free memory for dynamic Node ... */
/* now update size and return (by reference, since address passed in) */
-- cl->size;
}
/* pass in the address of the Clist and the new Node to insert ... */
void insert_sortedClist( Clist* list, pNode n )
{
pNode head;
if( !list->isSorted ) msortClist( list );
head = list->start;
/* firstly, we handle most common case where 'n' is NOT the first Node */
if( head != NULL && strcmp( n->str, head->str ) >= 0 ) /* NEED >= */
{
/* so search the linked list for the right location */
pNode cur = head;
while( cur->next != NULL && strcmp( cur->next->str, n->str ) <= 0 )
{
cur = cur->next;
}
if( cur == list->end ) list->end = n;
n->next = cur->next;
cur->next = n;
/* list->start = head; // unchanged */
++ list->size;
}
else /* if we reach here, this IS the first node ... */
{
n->next = head; /* so set this node in first position */
list->start = n;
++ list->size;
if( list->size == 1 ) list->end = n;
}
}
void isortClist( Clist* list )
{
pNode cur,
nextNode;
Clist nClist;
initClist( &nClist );
for( cur = list->start; cur != NULL; cur = nextNode )
{
nextNode = cur->next; /* get copy here before next is changed below ...*/
insert_sortedClist( &nClist, cur ); /* 'cur' already is a Node pointer */
}
/* now ... update old list with new front and back ... */
list->start = nClist.start;
list->end = nClist.end;
list->isSorted = 1;
/* size hasn't changed ... */
}
#endif /* end of #ifndef dwClistOfString_H */
/* readLine2.h */ /* this version: 2016-10-09 */
/* http://developers-heaven.net/forum/index.php/topic,46.0.html */
/*
Safe string data entry from file ... to replace gets and fgets
BUT free new memory ... when done! Don't forget that C strings are
pointers to a block of char, with a '\0' char at the terminal end ...
Call like this:
char* line = readLine( stdin );
or ...
while( (line = readLine( FILEp )) )
{
// process line ...
}
*/
/* includes stdio.h, stdlib.h, string.h and myAssert and newCopy functions */
#ifndef dwREADLINE_H
#define dwREADLINE_H
/* can re-set/adjust here to best match your line-length */
#ifndef LINECHUNK
#define LINECHUNK 256
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h> /* re. isspace in trim ... */
#ifndef dwMYASSERT
#define dwMYASSERT
void myAssert( int condition, const char text[] )
{
if( !condition )
{
fprintf(stderr, "%s\n", text );
fputs( "Press 'Enter' to exit program ... ", stderr );
getchar();
exit(1);
}
}
#endif
#ifndef dwNEWMEMORY
#define dwNEWMEMORY
char* newMem( int bytes )
{
char* n = (char*) malloc( bytes ); /* cast for C++ compilers */
myAssert( (n != NULL), "Error: malloc failed in 'newMem' ... " );
return n;
}
#endif
#ifndef dwNEWCOPY
#define dwNEWCOPY
char* newCopy( const char* str )
{
char* n = newMem( strlen(str) + 1 ); /* cast for C++ compilers */
strcpy( n, str );
return n;
}
#endif
#ifndef dwNEWSUBSTR
#define dwNEWSUBSTR
#define newsubstr newSubStr
char* newsubstr( const char* str, int beg, int len )
{
char* n = newMem( len + 1 ); /* cast for C++ compilers */
strncpy( n, str+beg, len );
n[len] = 0;
return n;
}
#endif
#ifndef dwTRIM
#define dwTRIM
char* trim( char* s )
{
char *start = s, *end = s;
while( *end ) ++end ;
if( end == s ) return s; /* empty string */
for( --end; s <= end && isspace(*end); --end ) ;
end[1] = 0;
while( isspace(*s) ) ++s;
memmove( start, s, end+2-s ); /* 2 ... to copy terminal 0 */
return start;
}
char* rtrim( char* s )
{
char* end = s;
while( *end ) ++end ;
if( end == s ) return s; /* empty string */
for( --end; s <= end && isspace(*end); --end ) ;
end[1] = 0;
return s;
}
char* ltrim( char* s )
{
char *start = s, *end = s;
while( *end ) ++end ;
if( end == s ) return s; /* empty string */
while( isspace(*s) ) ++s;
memmove( start, s, end+1-s ); /* 1 ... to copy terminal 0 */
return start;
}
#endif
#ifndef dwUPDOWN
#define dwUPDOWN
char* strToUpper( char* str )
{
char* p = str;
while( *p != 0 ) { *p = toupper(*p); ++p; }
return str;
}
char* strToLower( char* str )
{
char* p = str;
while( *p != 0 ) { *p = tolower(*p); ++p; }
return str;
}
char* strToUpperFirstLetter( char* str )
{
if( str && strlen(str) )
str[0] = toupper(str[0]);
return str;
}
char* strToTitleCase( char* str )
{
char* p = strToLower(str);
char prev = ' ';
while( *p )
{
if( isspace(prev) ) *p = toupper( *p );
prev = *p;
++p;
}
return str;
}
#endif
#ifndef dwTAKE_IN_CHAR_MORE
#define dwTAKE_IN_CHAR_MORE
/* a handy utility for many C student coding problems ... */
char takeInChar( const char* msg )
{
char chr;
printf( msg ); fflush( stdout );
chr = getchar();
if( chr != '\n' ) while( getchar() != '\n' ) ; /* flush stdin ... */
return chr;
}
int more() /* defaults to 'true'/'yes'/'1' ... unless 'n' or 'N' entered */
{
if( tolower( takeInChar( "More (y/n) ? " )) == 'n' ) return 0;
/* else ... */
return 1;
}
#endif
/* returns a string in new memory holding each word ... or NULL if EOF */
char* readLine( FILE* fp )
{
int c, cap = LINECHUNK, size = 0; /* c to hold each char ... */
void* tmp;
char* strData = (char*) malloc( cap ); /* cast for C++ compilers ... */
myAssert( (strData != NULL), "Error: malloc failed at top of 'readLine' ... " );
while( (c = fgetc(fp)) != '\n' && c != EOF )
{
if( size == cap-1 ) /* skip while size < cap-1 */
{
cap += cap; /* double memory capacity ... */
if( (tmp = realloc(strData, cap)) == NULL )
{
free(strData);
myAssert( 0, "Error: realloc failed in 'readLine' ... " );
}
/* else ... good realloc above, so update strData pointer */
strData = (char*) tmp;
}
/* now ... since reached here ... */
strData[size++] = c; /* append this char ... */
}
strData[size] = 0; /* '\0' terminate */
if( c == EOF && strData[0] == 0 ) { free(strData); return NULL; }
/* else ... since didn't return NULL above, compact string to right-size */
if( (tmp = realloc(strData, size+1)) == NULL ) /* size+1 to hold 0 at end */
{
free(strData);
myAssert( 0, "Error: realloc failed in compacting C string ... " );
}
return (char*) tmp; /* return the string with NO extra capacity ... */
}
char* readLine2( FILE* fp, unsigned* len )
{
int c, cap = LINECHUNK, size = 0; /* c to hold each char ... */
void* tmp;
char* strData = (char*) malloc( cap ); /* cast for C++ compilers ... */
myAssert( (strData != NULL), "Error: malloc failed at top of 'readLine' ... " );
while( (c = fgetc(fp)) != '\n' && c != EOF )
{
if( size == cap-1 ) /* skip while size < cap-1 */
{
cap += cap; /* double memory capacity ... */
if( (tmp = realloc(strData, cap)) == NULL )
{
free(strData);
myAssert( 0, "Error: realloc failed in 'readLine' ... " );
}
/* else ... good realloc above, so update strData pointer */
strData = (char*) tmp;
}
/* now ... since reached here ... */
strData[size++] = c; /* append this char ... */
}
strData[size] = 0; /* '\0' terminate */
if( c == EOF && strData[0] == 0 ) { free(strData); return NULL; }
/* else ... since didn't return NULL above, compact string to right-size */
if( (tmp = realloc(strData, size+1)) == NULL ) /* size+1 to hold 0 at end */
{
free(strData);
myAssert( 0, "Error: realloc failed in compacting C string ... " );
}
*len = size;
return (char*) tmp; /* return the string with NO extra capacity ... */
}
#endif
/* readWord2.h */ /* this ver 2016-10-09 */
/* http://developers-heaven.net/forum/index.php/topic,46.0.html */
/*
Safe string data entry from file or keyboard ...
BUT ... free new memory when done with it!
Don't forget that C strings are pointers to a block of char,
with a '\0' char at the terminal end ... Call like this:
char* word = readWord(stdin, 31, "\n\t ,.;:", &lastChr);//note delimiter str
or ...
while((word = readWord(FILEp, startChunkSize, delimiterStr, &lastCharRead)))
{
// do stuff ...
}
Note 1: select your initial word chunk size to minimize calls to realloc
Note 2: address of last char passed in/out so can flush stdin or file line
*/
#ifndef dwREADWORD_H
#define dwREADWORD_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* re. strchr */
#include <ctype.h> /* re. isspace in trim ... */
#ifndef dwMYASSERT
#define dwMYASSERT
void myAssert( int condition, const char text[] )
{
if( !condition )
{
fprintf(stderr, "%s\n", text );
fputs( "Press 'Enter' to exit program ... ", stderr );
getchar();
exit(1);
}
}
#endif
#ifndef dwNEWMEMORY
#define dwNEWMEMORY
char* newMem( int bytes )
{
char* n = (char*) malloc( bytes ); /* cast for C++ compilers */
myAssert( (n != NULL), "Error: malloc failed in 'newMem' ... " );
return n;
}
#endif
#ifndef dwNEWCOPY
#define dwNEWCOPY
char* newCopy( const char* str )
{
char* n = newMem( strlen(str) + 1 ); /* cast for C++ compilers */
strcpy( n, str );
return n;
}
#endif
#ifndef dwNEWSUBSTR
#define dwNEWSUBSTR
#define newsubstr newSubStr
char* newsubstr( const char* str, int beg, int len )
{
char* n = newMem( len + 1 ); /* cast for C++ compilers */
strncpy( n, str+beg, len );
n[len] = 0;
return n;
}
#endif
#ifndef dwTRIM
#define dwTRIM
char* trim( char* s )
{
char *start = s, *end = s;
while( *end ) ++end ;
if( end == s ) return s; /* empty string */
for( --end; s <= end && isspace(*end); --end ) ;
end[1] = 0;
while( isspace(*s) ) ++s;
memmove( start, s, end+2-s ); /* 2 ... to copy terminal 0 */
return start;
}
char* rtrim( char* s )
{
char* end = s;
while( *end ) ++end ;
if( end == s ) return s; /* empty string */
for( --end; s <= end && isspace(*end); --end ) ;
end[1] = 0;
return s;
}
char* ltrim( char* s )
{
char *start = s, *end = s;
while( *end ) ++end ;
if( end == s ) return s; /* empty string */
while( isspace(*s) ) ++s;
memmove( start, s, end+1-s ); /* 1 ... to copy terminal 0 */
return start;
}
#endif
#ifndef dwUPDOWN
#define dwUPDOWN
char* strToUpper( char* str )
{
char* p = str;
while( *p != 0 ) { *p = toupper(*p); ++p; }
return str;
}
char* strToLower( char* str )
{
char* p = str;
while( *p != 0 ) { *p = tolower(*p); ++p; }
return str;
}
char* strToUpperFirstLetter( char* str )
{
if( str && strlen(str) )
str[0] = toupper(str[0]);
return str;
}
char* strToTitleCase( char* str )
{
char* p = strToLower(str);
char prev = ' ';
while( *p )
{
if( isspace(prev) ) *p = toupper( *p );
prev = *p;
++p;
}
return str;
}
#endif
#ifndef dwTAKE_IN_CHAR_MORE
#define dwTAKE_IN_CHAR_MORE
/* a handy utility for many C student coding problems ... */
char takeInChar( const char* msg )
{
char chr;
printf( msg ); fflush( stdout );
chr = getchar();
if( chr != '\n' ) while( getchar() != '\n' ) ; /* flush stdin ... */
return chr;
}
int more() /* defaults to 'true'/'yes'/'1' ... unless 'n' or 'N' entered */
{
if( tolower( takeInChar( "More (y/n) ? " )) == 'n' ) return 0;
/* else ... */
return 1;
}
#endif
/* returns a string into new memory to hold each word ...
or NULL if EOF */
char* readWord( FILE* fp, int chunk_len, const char delimits[], char* c)
{
char *strData, *tmp;
int i = 0; /* i for index in string, *c to hold each char */
if( chunk_len < 4 )
chunk_len = 4; /* set to min. starting chunk size */
else if( chunk_len %4 )
chunk_len = chunk_len + ( 4 - chunk_len%4 );
/* cast added for C++ compilers */
strData = (char*) malloc( chunk_len );
myAssert( (strData != NULL), "Error: malloc failed in readWord (1)" );
while( ( *c = fgetc( fp )) != EOF && strchr( delimits, *c ))
; /* advance over any whitespace i.e. delimits */
if( *c != EOF ) /* ok ... get this first char ... */
strData[i++] = *c;
else
{
free( strData );
return NULL; /* at EOF or all 'delimits' ... */
}
while( (*c = fgetc( fp )) != EOF && !strchr( delimits, *c ) )
{
if( i == chunk_len-1 ) /* skip while i <= chunk_len-2 */
{
chunk_len += chunk_len; /* double memory ...*/
if( ( tmp = (char*) realloc( strData, chunk_len )) == NULL )
{
free( strData );
myAssert( 0, "Error: realloc failed in readWord (2)" );
}
/* if reach here, realloc above was a success,
so update strData */
strData = tmp;
}
/* now can ... */
strData[i++] = *c;
}
strData[i] = 0; /* assure '\0' termination */
/* if EOF and empty strData, quit reading file,
BUT FIRST, free this strData */
if( *c == EOF && strData[0] == 0 )
{ free( strData ); return NULL; }
/* else ... and note ... i is index of '\0' */
if( (tmp = (char*) realloc( strData, i+1 )) == NULL )
{
free( strData );
myAssert( 0, "Error: realloc failed in readWord (3)" );
}
/* if reach here, realloc above was a success, program NOT aborted, so ...*/
return tmp;
}
char* readWord2( FILE* fp, int chunk_len, const char delimits[], char* c, unsigned* len )
{
char *strData, *tmp;
int i = 0; /* i for index in string, *c to hold each char */
if( chunk_len < 4 )
chunk_len = 4; /* set to min. starting chunk size */
else if( chunk_len %4 )
chunk_len = chunk_len + ( 4 - chunk_len%4 );
/* cast added for C++ compilers */
strData = (char*) malloc( chunk_len );
myAssert( (strData != NULL), "Error: malloc failed in readWord (1)" );
while( ( *c = fgetc( fp )) != EOF && strchr( delimits, *c ))
; /* advance over any whitespace i.e. delimits */
if( *c != EOF ) /* ok ... get this first char ... */
strData[i++] = *c;
else
{
free( strData );
return NULL; /* at EOF or all 'delimits' ... */
}
while( (*c = fgetc( fp )) != EOF && !strchr( delimits, *c ) )
{
if( i == chunk_len-1 ) /* skip while i <= chunk_len-2 */
{
chunk_len += chunk_len; /* double memory ...*/
if( ( tmp = (char*) realloc( strData, chunk_len )) == NULL )
{
free( strData );
myAssert( 0, "Error: realloc failed in readWord (2)" );
}
/* if reach here, realloc above was a success,
so update strData */
strData = tmp;
}
/* now can ... */
strData[i++] = *c;
}
strData[i] = 0; /* assure '\0' termination */
/* if EOF and empty strData, quit reading file,
BUT FIRST, free this strData */
if( *c == EOF && strData[0] == 0 )
{ free( strData ); return NULL; }
/* else ... and note ... i is index of '\0' */
if( (tmp = (char*) realloc( strData, i+1 )) == NULL )
{
free( strData );
myAssert( 0, "Error: realloc failed in readWord (3)" );
}
/* if reach here, realloc above was a success, program NOT aborted, so ...*/
*len = i;
return tmp;
}
#endif