Developers Heaven Forum

Desktop Programming => C/C++ & Visual C++ => Topic started by: David on May 27, 2013, 01:27:36 AM

Title: C SOME UTILITY functions ...
Post by: David on May 27, 2013, 01:27:36 AM
This space is reserved for code and links to code for C utility functions ...

After I have collected several C snippets here ...  I hope to make an index with links on this front page.

But for now, please find these little snippets of code below,  (perhaps in related usage groupings of code, on the following pages.)


Update: please see this next link:

http://developers-heaven.net/forum/index.php/topic,2636.0.html


FREE homework help NOW available ...

You can contact me via:
http://sites.google.com/site/andeveryeyeshallseehim/home/he-comes
http://developers-heaven.net/forum/index.php/topic,2587.0.html


You may also like to see:  C++ SOME UTILITY functions ...

http://developers-heaven.net/forum/index.php/topic,2611.0.html


Update 2015-04-08: 

SEE the next link for several newly improved STUDENT take in type utilities  ...
with out of bounds error handling ...
(Some VERY HANDY student utilities.)

http://developers-heaven.net/forum/index.php/topic,2608.msg3158.html#msg3158


1.  /* example of a way to fix fgets TWO sometimes very annoying problems   */
char* fixedFgets( char* str, size_t bufSize, FILE* fin );

2.  /* example of a way to trim leading and trailing ws ... */
char* stripWS( char* s );

3.  /* example of an expedient way in C to handle string input from keyboard operator ...
    especially, if design calls to repeat input until string is of 'acceptable length' */
char* takeInStr( const char* msg, char* buf, unsigned bufLen, unsigned maxStrLen );

4.  /* an example of a common design request ... to Caps on first letters */
char* toCapsOnFirstLets( char* str );

5.  /* a simple student way to handle numeric input ...
   so program won't crash on bad input */
int takeInInt( const char* msg, int myMin, int myMax );

6.  /* loop until user takes in a valid int ... after prompt(s) ...  */
int takeInValidInt( const char prompt[] );

7.  /* a handy utility for many C student coding problems ... */
char takeInChar( const char* msg );

8.  int more(); /* defaults to 'true'/'yes'/'1' ... unless 'n' or 'N' entered */

9.  /* since using 'static' buf inside, memory persists ... so can return address */
char* takeInStaticString( const char* msg, unsigned max_len );

10. /* accepts only positive (i.e. >= 0) valid int range of values ... */
int takeInValidPosIntViaStaticString( const char* prompt, int high );

11. /*  returns a valid int in range INT_MIN..INT_MAX  */
int takeInValidMinMaxIntViaStaticString( const char* prompt, int myMin, int myMax );

...

And more added below ... like binary search, an iterative and also a recursive example, date and time and valid date and valid dob and days between two dates and ...


Code: [Select]
/* returns 'int' value if in range '0'..'9' else returns -1 if NOT a digit */

int getDigit( char c )
{
    if ( c < '0' || c > '9' ) return -1;
    return c - '0';
}

/*
    Note: int( c ), where c is a char in the range '0'..'9'
    would return integers in the range 48..57
    ... but getDigit( c ) returns integers in the range 0..9
*/


Code: [Select]
/* returns int value if in range '0'..'9' else returns -1 if not a number */

int isNum( char c )
{
    if ( c < '0' || c > '9' ) return -1;
    return c - '0';
}



1.  Six Fast Steps to Programming in C

http://developers-heaven.net/forum/index.php/topic,2022.0.html


2.  CvecOfInt.h, CvecOfString.h, Cvec.h, Cvec_func's.h (with FUNCTION POINTERS)

http://developers-heaven.net/forum/index.php/topic,2580.0.html


3.  Cvec_func's.h example programs ... using FUNCTION POINTERS to facilitate reuse

http://developers-heaven.net/forum/index.php/topic,2581.0.html


4. ClistOfInt.h, ClistOfString.h, Clist.h, Clist_func's.h (with FUNCTION POINTERS)

http://developers-heaven.net/forum/index.php/topic,2582.0.html


5.  Clist_func's.h example programs ... using FUNCTION POINTERS to facilitate reuse

http://developers-heaven.net/forum/index.php/topic,2583.0.html


6.  split.h ... a C emulation of the Python spilt function to parse a string ...

http://developers-heaven.net/forum/index.php/topic,2584.0.html


7.  Binary Search Tree template class in C ++ and Simple C Version

http://developers-heaven.net/forum/index.php/topic,2605.0.html


8.  Beyond Beginning Computer Programming in C ...

http://developers-heaven.net/forum/index.php/topic,2598.0.html


9.  Send in your C++ or C student coding problem, with code inside code tags (#)

http://developers-heaven.net/forum/index.php/topic,2473.0.html


10. Free coding help for beginners in C or C++

http://developers-heaven.net/forum/index.php/topic,2575.0.html


11. Clist Insertion Sort Tutorial ... and also see a recursive merge sort of a list

http://developers-heaven.net/forum/index.php/topic,2440.0.html


12. First steps ... via example programs in C++ and C ...

http://developers-heaven.net/forum/index.php/topic,134.0.html


13. New thread especially for students of C and C++

http://developers-heaven.net/forum/index.php/topic,106.0.html


14. BEGINNING COMPUTER PROGRAMMING (using C++ or C)

http://developers-heaven.net/forum/index.php/topic,127.0.html
Title: Re: C SOME UTILITY functions ...
Post by: David on May 27, 2013, 01:30:05 AM
/*
    Example of a way to fix fgets sometimes TWO very annoying problems:

    1.  a 'maybe' newline at the end of the input buffer string ...
    2.  the possibility of the input string being TOO LONG for the input buffer C string

*/

Code: [Select]
#include <stdio.h>
#include <string.h>

char* fixedFgets( char* str, size_t bufSize, FILE* fin )
{
    if( fgets( str, bufSize, fin ) )
    {
        char *p = strchr( str, '\n' ), c ;
        if( p ) *p = 0; /* strip off '\n' at end ... IF it exists */
        else while( (c = fgetc( fin )) != '\n'  &&  c != EOF ) ; /* flush ... */
        return str;
    }
    else return NULL;
}


/* example of a way to trim leading and trailing ws ... */

Code: [Select]
#include <string.h>
#include <ctype.h>

char* stripWS( char* s )
{
    char *start = s, *end = s;
    while( *end ) ++end ;
    if( end == start ) 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;
}


/*
    Take in string into buf string passed in of bufLen, but limit allowed input string length to maxStrLen
    Example of an expedient way in C to handle string input from keyboard operator ...
    especially, if design calls to repeat input until string is of 'acceptable length'

*/
Code: [Select]
char* takeInStr( const char* msg, char* buf, unsigned bufLen, unsigned maxStrLen )
{
    unsigned len = 0;
    if( maxStrLen < bufLen )
    {
        for( ; ; ) /* on example of a C 'forever loop' ...
                      until break from loop or return from function */
        {
            printf( msg ); fflush( stdout );
            fixedFgets( buf, bufLen, stdin );
            stripWS( buf );
            len = strlen( buf );
            if( len  &&  len <= maxStrLen ) return buf;
            else
            {
                if( len ) printf( "\nError! myMax input string length here "
                                  "is %d char's long ...\n"
                                  "but your string was %d char's long.\n",
                                  maxStrLen, len );
                else printf( "\nBlank lines NOT valid input here ...\n" );
            }
        }
    }
    /* else ... */
    printf( "\nERROR!  The bufLen of %d needs to be greater than %d\n",
            bufLen, maxStrLen );
    return NULL;
}


/* an example of a common design request ...  to ensure Caps on all 'first letters' */

Code: [Select]
char* toCapsOnFirstLets( char* str )
{
    char *p = str, prev = ' ';
    for( ; *p ; ++p )
    {
        if( prev == ' ' || prev == '\t' )
            *p = toupper( *p );
        prev = *p;
    }
    return str;
}
Title: Re: C SOME UTILITY functions ...
Post by: David on May 27, 2013, 01:38:21 AM
/*
   Some simple student ways to handle validating numeric input ...
   and to code so that program won't crash on invalid numeric input
*/


/*
   loop until user takes in a valid int ... after prompt(s) ... 
   int here is also checked and accepted iff in int range myMin..myMax
   
   uses scanf for input

   int takeInIntMinMax( const char* msg, int myMin, int myMax );
*/

Code: [Select]
#include <stdio.h>
 
/* loop until user takes in a valid int ... after prompt(s) ...  */
/* int here is also checked and accepted iff in int range myMin..myMax */
int takeInIntMinMax( const char* msg, int myMin, int myMax )
{
    int goodVal = 0, val = 0;
   
    while( !goodVal )
    {
    /* show prompt for input ...
   fflush( stdout) ensures prompt displayed right NOW
*/
        printf( msg ); fflush( stdout );
       
        /* Note logic below ...

   if scanf returns 1 below means ...
   ***there WAS ONE***
   good int data presented at first in input stream
       
           then ... if getchar() == '\n'
   ***that means that '\n' WAS the VERY NEXT CHAR***
   
   which means no space or other chars entered there
   before a '\n' char was entered ...
   so ... ***WAS good int*** data presented
   i.e. no 'junk' was entered by user 'by accident'
        (after int data was entered and before '\n' pressed)
*/

        if( scanf( "%d", &val ) == 1 && getchar() == '\n' )
        {
        goodVal = 1; /* Ok ... good so far ... */
        }
        else
        {
            printf( "\nInteger input only here please ...\n" );
            while( getchar() != '\n' ) ; /* flush stdin ... */
        }
       
        /* NOW check if input val was in the desired range myMin..myMax */

        if( goodVal && ( val < myMin || val > myMax ) )
        {
            goodVal = 0; /* reset to 'false' since val NOT in desired range */
            printf( "\nValid input only in range %d..%d\n", myMin, myMax );
        }
       
    } /* end while ... */   
   
    return val;
}



/*
   loop until user takes in a valid int ... after prompt(s) ...

   uses scanf for input

   int takeInValidInt( const char prompt[] );
*/

Code: [Select]
#include <stdio.h>

/* loop until user takes in a valid int ... after prompt(s) ...  */
int takeInValidInt( const char prompt[] )
{
    for( ; ; ) /* an other example of a C/C++ forever loop ... until 'return' */
    {
        int testInt;
        printf( prompt ); fflush( stdout );
       
       
        if( scanf( "%d", &testInt ) == 1 && getchar() == '\n' )
        {
        return testInt; /* since passed BOTH above checks ... */
        }
       
        /*else ... if reach here means failed either 1st or 2nd of above checks */
        while( getchar() != '\n' ); /* so ... 'flush' stdin ... as you go ... */
       
        puts( "Invalid input! Integers only please ..." );
    }
}



Code: [Select]
#include <stdio.h>
#include <ctype.h> /* re. tolower */

char takeInChar( const char* msg )
{
    char chr;
    printf( msg ); fflush( stdout );
    chr = getchar();
    if( chr != '\n' ) while( getchar() != '\n' ) ; /* flush stdin ... */
    return chr;
}


Code: [Select]
int more() /* defaults to 'true'/'yes'/'1' ... unless 'n' or 'N' entered */
{
    if( tolower( takeInChar( "\nMore (y/n) ? " )) == 'n' ) return 0;
    /* else ... */
    return 1;
}

readLine is readily available by including file readLine.h

http://developers-heaven.net/forum/index.php/topic,2580.msg2864.html#msg2864
Title: Re: C SOME UTILITY functions ...
Post by: David on May 28, 2013, 08:15:33 AM
A little test program featuring taking in a (fully) validated integer, (looping until have an input string that fits into an int), via taking in a STATIC C string and using atoi to convert to an int after validating that all are valid char's in the input string ... (in TWO Files ... a test program ... and a .h file that follows that needs to be included)

Code: [Select]
/* test_takeInStaticStringUtilities.h.c */  /* revised 2013-06-08 */


#include "takeInStaticStringUtilities.h"


int main()
{
int count = 0;
double sum = 0.0;

printf( "MAX number of digits, permitted in an 'int' here, is %d\n",
MAX_DIG_IN_INT );

printf( "\nINT_MIN = %d, INT_MAX  = %d\n\n", INT_MIN, INT_MAX );

do
{
sum += takeInValidPosIntViaStaticString(
"Enter next integer >= 0 to sum: ", INT_MAX );
++ count;
}
while( more() ); /* make sure stdin is 'empty' before calling 'more()' */


printf( "\nFor %d numbers entered, sum was %.0f and average was %.2f\n",
count, sum, sum/count );

count = 0;
sum = 0.0;

putchar( '\n' );

do
{
sum += takeInValidMinMaxIntViaStaticString(
"Enter next integer to sum: ", INT_MIN, INT_MAX );
++ count;
}
while( more() ); /* make sure stdin is 'empty' before calling 'more()' */

printf( "\nFor %d numbers entered, sum was %.0f and average was %.2f\n",
count, sum, sum/count );


/* keep 'Window' open until 'Enter' key is pressed ... */
takeInChar( "\nPress 'Enter' to continue/exit ... " );
return 0;
}



Code: [Select]
/* takeInStaticStringUtilities.h */  /* 2013-06-08 */


/* http://developers-heaven.net/forum/index.php/topic,46.0.html */

#ifndef TAKE_IN_STATIC_STR_UTILITIES
#define TAKE_IN_STATIC_STR_UTILITIES

#include <stdio.h>
#include <stdlib.h>  /* re. atoi ... */
#include <string.h> /* re. strlen, strcpy, strchr... */
#include <ctype.h> /* re. tolower... */
#include <limits.h> /* re. INT_MAX, INt_MIN */
#include <math.h> /* re. log10 ... */

#define BIG_BUF_LEN 1024


#define MAX_DIG_IN_INT ( (int) log10( INT_MAX ) + 1 )


#ifndef dwTAKE_IN_CHAR_MORE
#define dwTAKE_IN_CHAR_MORE

int takeInChar( const char* msg )
{
int reply;
fputs( msg, stdout ); fflush( stdout );
reply = getchar();
if( reply != '\n' )
while( getchar() != '\n' ) ; /* 'flush' stdin buffer */
return reply;
}

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


/* since using 'static' buf inside, memory persists ... so can return address */
char* takeInStaticString( const char* msg, unsigned max_len )
{
static char buf[BIG_BUF_LEN];
char* p = NULL;

for( ; ; )
{
fputs( msg, stdout ); fflush( stdout );

fgets( buf, BIG_BUF_LEN, stdin );

/* Now 'fix' fgets input string or stdin
i.e. fix what needs 'fixing') */

p = strchr( buf, '\n' );
if( p ) /* strip off '\n' char if present */
*p = 0;
else /* flush stdin to end of line */
while( getchar() != '\n' );


if( buf[0] && strlen( buf ) <= max_len )
break;
else if( !buf[0] ) printf( "\nBlank line NOT valid input here ... \n" );
else printf( "\nFor '%s', max len of %u char's was exceeded ... \n",
buf, max_len );
}

return buf;
}


/* accepts only positive (i.e. >= 0) valid int range of values ... */
int takeInValidPosIntViaStaticString( const char* prompt, int high )
{
char loc_buf[32], *tmpStr;
int good = 0, i = 0, len = 0, tmpInt = 0;

for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
{
tmpStr = takeInStaticString( prompt, MAX_DIG_IN_INT );
len =  i = strlen( tmpStr );
good = ( i > 0 );
while( good && --i >= 0 )
{
if( !isdigit( tmpStr[i] ) ) { good = 0; break; }
}

if( good && len == MAX_DIG_IN_INT )
{
sprintf( loc_buf, "%d", INT_MAX );
if( strcmp( tmpStr, loc_buf ) > 0 ) good = 0;
}

if( good && tmpInt <= high )
{
tmpInt = atoi( tmpStr );
break;
}
/*else ...*/
printf( "\nInvalid input! Integers only please, in valid range 0..%d\n",
high );
}
return tmpInt;
}

/*  returns a valid int in range INT_MIN..INT_MAX */
int takeInValidMinMaxIntViaStaticString( const char* prompt, int myMin, int myMax )
{
char loc_buf[32];
int tmpInt;

for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
{
int good = 1, i = 0, len = 0, sign = 1;
char* tmp = takeInStaticString( prompt, MAX_DIG_IN_INT+1 ); /* leave room for + - */

if( tmp[0] == '+' ) ++tmp;
else if( tmp[0] == '-') { ++tmp; sign = -1; }

len = i = strlen( tmp );
good = ( i > 0 && i <= MAX_DIG_IN_INT );
while( good && --i >= 0 )
{
if( !isdigit( tmp[i] ) ) good = 0;
}

if( good && len == MAX_DIG_IN_INT )
{
if( sign == 1 )
{
sprintf( loc_buf, "%d", INT_MAX );
if( strcmp( tmp, loc_buf ) > 0 ) good = 0;
}
else
{
sprintf( loc_buf, "%d", INT_MIN );
if( strcmp( tmp, &loc_buf[1] ) > 0 ) good = 0;
}
}

if( good )
{
tmpInt = sign * atoi( tmp );
if( tmpInt >= myMin && tmpInt <= myMax ) break;
}
/*else ...*/
printf( "\nInvalid input! Integers please, only in range %d..%d\n",
myMin, myMax );
}
return tmpInt;
}

#endif



Now a little different set of C utilities all in a .h file and a little test program follows ...

/*
    features ... an expedient way in C to handle string input from keyboard operator ...
    especially, if design calls to repeat input until string is of 'acceptable length'

    using a passed in C string 'buf' with passed in length of 'bufLen'

    char* takeInStr( const char* msg, char* buf, unsigned bufLen, unsigned maxStrLen );

    int takeInValidIntViaStrBuf( const char* msg );

    int takeInValidIntViaStrBufInRangeMinMax( const char* msg, int min, int max );
*/

Code: [Select]
/* Cutilities.h */  /* 2016-06-20 */

#ifndef CUTILITIES_H
#define CUTILITIES_H


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <limits.h>

#define MAX_DIG_IN_INT (int)( log10( INT_MAX ) + 1 )


#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

#ifndef dwFIXEDFGETS
#define dwFIXEDFGETS

/* example of a way to fix fgets TWO, sometimes very annoying, problems */
char* fixedFgets( char* s, size_t bufSize, FILE* fin )
{
    if( fgets( s, bufSize, fin ) )
    {
        char *p = strchr( s, '\n' ),
             c ;
        if( p ) *p = 0; /* strip off '\n' at end ... iF it exists */
        else while( (c = fgetc( fin )) != '\n'  &&  c != EOF ) ; /* flush... */
        return s;
    }
    /*  else ... if reach here ... */
    return NULL;
}


#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 dwTOCAPSONFIRSTLETS
#define dwTOCAPSONFIRSTLETS

/* an example of a common design request ... */
char* toCapsOnFirstLets( char* str )
{
    char* p = str;
    char prev = ' ';
    while( *p )
    {
        if( prev == ' ' ) *p = toupper( *p );
        prev = *p;
        ++p;
    }
    return str;
}

#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;
}
#endif

/*
    example of an expedient way in C to handle string input from keyboard operator ...
    especially, if design calls to repeat input until string is of 'acceptable length'

*/
char* takeInStr( const char* msg, char* buf, unsigned bufLen, unsigned maxStrLen )
{
    unsigned len = 0;
    if( maxStrLen < bufLen )
    {
        for( ; ; ) /* on example of a C 'forever loop' ...
                      until break from loop or return from function */
        {
            printf( msg ); fflush( stdout );
            fixedFgets( buf, bufLen, stdin );
            trim( buf );
            len = strlen( buf );
            if( len  &&  len <= maxStrLen ) return buf;
            else
            {
                if( len ) printf( "\nError! myMax input string length here "
                                  "is %d char's long ...\n"
                                  "but, your string was %d char's long.\n",
                                  maxStrLen, len );
                else printf( "\nBlank lines NOT valid input here ...\n" );
            }
        }
    }
    /* else ... */
    printf( "\nERROR!  The bufLen of %d needs to be greater than %d\n",
            bufLen, maxStrLen );
    return NULL;
}


/* a simple student way to handle numeric input ...
   so program won't crash on bad input */
int takeInValidIntInRangeMinMax( const char* msg, int myMin, int myMax )
{
    int good = 0, val = 0;
    while( !good )
    {
        printf( msg ); fflush( stdout );

        if( scanf( "%d", &val ) == 1 && getchar() == '\n' ) good = 1;
        else
        {
            printf( "\nInteger input only here please ...\n" );
            while( getchar() != '\n' ) ; /* flush stdin ... */
        }

        if( good &&  val >= myMin && val <= myMax ) break;
        else
        {
            good = 0;
            printf( "\nValid input only in range %d..%d\n", myMin, myMax );
        }
    }
    return val;
}

int takeInValidInt( const char* msg )
{
    int val = 0;
    while( 1 )
    {
        printf( msg ); fflush( stdout );

        if( scanf( "%d", &val ) == 1 && getchar() == '\n' )
        {
        return val;
        }
        /* else ... **/
       
        printf( "\nInteger input only here please ...\n" );
        while( getchar() != '\n' ) ; /* flush stdin ... */ 
    }
}

int takeInValidIntViaStrBuf( const char* msg )
{
char loc_buf[32], loc_buf2[32], *tmpStr;
int good = 1, i = 0, len =0, sign = 1, tmpInt = 0;

for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
{

/* NOTE: blank lines NOT allowed as input below... and leave room for + -  */
tmpStr = takeInStr( msg, loc_buf, sizeof(loc_buf), MAX_DIG_IN_INT+1 );

/* handle sign if present ... */
if( tmpStr[0] == '+' ) ++tmpStr;
else if( tmpStr[0] == '-') { ++tmpStr; sign = -1; }

len = i = strlen( tmpStr );

/* make sure has at least 1 dig ... and NOT too many dig's ... */
good = ( i > 0 && i <= MAX_DIG_IN_INT );

/* make sure all digits ... */
while( good && --i >= 0 )
{
if( !isdigit( tmpStr[i] ) ) { good = 0; break; }
}

/* make sure fits intn an int ...*/

if( good && len == MAX_DIG_IN_INT )
{
if( sign == 1 )
{
sprintf( loc_buf2, "%d", INT_MAX );
if( strcmp( tmpStr, loc_buf2 ) > 0 ) good = 0;
}
else
{
sprintf( loc_buf2, "%d", INT_MIN );
if( strcmp( tmpStr, &loc_buf2[1] ) > 0 ) good = 0;
}

}

if( good )
{
tmpInt = atoi( loc_buf );
break;
}
/*else ...*/
printf( "\nInvalid input! Integers please, only in range %d..%d\n",
INT_MIN, INT_MAX );
}

return tmpInt;
}

int takeInValidIntViaStrBufInRangeMinMax( const char* msg, int min, int max )
{
char loc_buf[32], loc_buf2[32], *tmpStr;
int good = 1, i = 0, len =0, sign = 1, tmpInt = 0;

for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
{

/* NOTE: blank lines NOT allowed as input below... and leave room for + -  */
tmpStr = takeInStr( msg, loc_buf, sizeof(loc_buf), MAX_DIG_IN_INT+1 );

/* handle sign if present ... */
if( tmpStr[0] == '+' ) ++tmpStr;
else if( tmpStr[0] == '-') { ++tmpStr; sign = -1; }

len = i = strlen( tmpStr );

/* make sure has at least 1 dig ... and NOT too many dig's ... */
good = ( i > 0 && i <= MAX_DIG_IN_INT );

/* make sure all digits ... */
while( good && --i >= 0 )
{
if( !isdigit( tmpStr[i] ) ) { good = 0; break; }
}

/* make sure fits intn an int ...*/

if( good && len == MAX_DIG_IN_INT )
{
if( sign == 1 )
{
sprintf( loc_buf2, "%d", INT_MAX );
if( strcmp( tmpStr, loc_buf2 ) > 0 ) good = 0;
}
else
{
sprintf( loc_buf2, "%d", INT_MIN );
if( strcmp( tmpStr, &loc_buf2[1] ) > 0 ) good = 0;
}
}

if( good )
        {
            tmpInt = atoi(loc_buf);
            if( tmpInt >=  min && tmpInt <= max  ) break;
        }
/* else ... */
printf( "\nERROR!  Valid input range here is %d..%d\n", min, max );
}
return tmpInt;
}


#endif



Code: [Select]
/* test_Cutilities.c */  /*  2013-07-11 */


#include "Cutilities.h"

void test_takeInStr()
{
char loc_buf[32];
char* tmp = takeInStr( "Enter your name(s): ",
loc_buf, sizeof(loc_buf), sizeof(loc_buf)-1 );

printf( "The string that was taken in was : '%s'\n", tmp );

toCapsOnFirstLets( tmp );
printf( "With CAPS On All First Letters   : '%s'\n", tmp );
}

void test_takeInValidInt()
{
int tmp = takeInValidInt( "Enter an int: " );
printf( "You entered %d\n", tmp );
}

void test_takeInValidIntInRangeMinMax()
{
char loc_buf[128];
int min = takeInValidInt( "Enter min value to accept: " );
int max = 0, tmpInt = 0;

while( ( max = takeInValidInt( "Enter max value to accept: " )) < min )
{
printf( "\nERROR!  Valid inout range here if %d..%d\n", min, INT_MAX );
}

/* form message ...*/
sprintf( loc_buf, "Enter integer in range %d..%d: ", min, max );
tmpInt = takeInValidIntInRangeMinMax( loc_buf, min, max );
printf( "You entered %d\n", tmpInt );
}

void test_takeInValidIntViaStringBuf()
{
int tmpInt = takeInValidIntViaStrBuf( "Enter a valid int: " );
printf( "You entered %d\n", tmpInt );
}

void test_takeInValidIntViaStrBufInRangeMinMax()
{
char loc_buf[128];
int min = takeInValidIntViaStrBuf( "Enter min value to accept: " );
int max = 0, tmpInt = 0;

while( ( max = takeInValidIntViaStrBuf( "Enter max value to accept: " )) < min )
{
printf( "\nERROR!  Valid inout range here if %d..%d\n", min, INT_MAX );
}

/* form message ...*/
sprintf( loc_buf, "Enter integer in range %d..%d: ", min, max );

tmpInt = takeInValidIntViaStrBufInRangeMinMax( loc_buf, min, max );
printf( "You entered %d\n", tmpInt );
}





int main()
{
printf( "INT_MIN = %d,  INT_MAX = %d\n\n", INT_MIN, INT_MAX );
printf( "Max mumber of digits permitted in an 'int' here is %d\n\n",
MAX_DIG_IN_INT );

do
{
puts( "Testing 'takeInStr( buf, bufLen, maxStrLen )' ..." );
test_takeInStr();

puts( "\nTesting 'takeInInt( msg )' ..." );
test_takeInValidInt();

puts( "\nTesting 'takeInValidIntInRangeMinMax( msg, min, max )' ..." );
test_takeInValidIntInRangeMinMax();

puts( "\nTesting 'takeInValidIntViaStringBuf( msg )' ..." );
test_takeInValidIntViaStringBuf();

puts( "\nTesting 'takeInValidIntViaStrBufInRangeMinMax( msg, min, max )' ..." );
test_takeInValidIntViaStrBufInRangeMinMax();

putchar( '\n' );
}
while( tolower( takeInChar( "\nMore (y/n) ? " )) != 'n' );
return 0;
}
Title: Re: C SOME UTILITY functions ...
Post by: David on May 29, 2013, 10:00:30 AM
Two files of several utilities that you may like to have to include ... the first uses fgets ... the 2nd uses readLine


Code: [Select]
/* fixedFgets.h */ /* 2012-06-01 */

/* updated to also have dwUPDOWN strToUpper and strToLower on 2013-04-03 */

#ifndef FIXEDFGETS_H
#define FIXEDFGETS_H

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>


#ifndef MAX_LINE_LEN
#define MAX_LINE_LEN 1023
#endif

#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 );
    strcpy( n, str );
    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;
}
#endif



char* fixedFgets( char* s, size_t bufSize, FILE* fin )
{
    if( fgets( s, bufSize, fin ) )
    {
        char *p = strchr( s, '\n' ), c ;
        if( p ) *p = 0; /* strip off '\n' at end ... IF it exists */
        else while( (c = fgetc( fin )) != '\n'  &&  c != EOF ) ; /* flush... */
        return s;
    }
    else return NULL;
}

char* newFgets( FILE* fin )
{
    char buf[MAX_LINE_LEN+1];
   
    if( fgets( buf, sizeof(buf), fin ) )
    {
        char *p = strchr( buf, '\n' ), c ;
        if( p ) *p = 0; /* strip off '\n' at end ... IF it exists */
        else while( (c = fgetc( fin )) != '\n'  &&  c != EOF ) ; /* flush... */
        return newCopy( buf );
    }
    else return NULL;
}

#endif


Code: [Select]
/* takeIn_readLine_utilities.h */  /* 2015-06-21 */


#ifndef TAKEIN_READLINE_UTILITIES_H
#define TAKEIN_READLINE_UTILITIES_H


#include <math.h>
#include <limits.h>
#include "readLine.h" /* see readLine.h to see all that is included ... */


#define MAX_DIG_IN_INT (int)( log10( INT_MAX ) + 1 )


#ifndef dwTAKE_IN_CHAR_MORE
#define dwTAKE_IN_CHAR_MORE

int takeInChar( const char* msg )
{
int reply;
fputs( msg, stdout ); fflush( stdout );
reply = getchar();
if( reply != '\n' )
while( getchar() != '\n' ) ; /* 'flush' stdin buffer */
return reply;
}

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


#ifndef dwTOCAPSONFIRSTLETS
#define dwTOCAPSONFIRSTLETS

/* an example of a common design request ... */
/* an example of a common design request ... */
char* toCapsOnFirstLets( char* str )
{
    char* p = str;
    char prev = ' ';
    while( *p )
    {
        if( prev == ' ' ) *p = toupper( *p );
        prev = *p;
        ++p;
    }
    return str;
}

#endif

/* using readLine and getting new dynamic memory  ... so can return address */
char* takeInStrMaxLen( const char* msg, unsigned maxLen )
{
char* p = NULL;

for( ; ; )
{
fputs( msg, stdout ); fflush( stdout );

p = readLine( stdin );

if( p[0] && strlen( p ) <= maxLen )
break;
else if( !p[0] ) printf( "\nBlank line NOT valid input here ... \n" );
else printf( "\nFor '%s', max len of %u char's was exceeded ... \n",
p, maxLen );
free( p );
}

return p;
}

char* takeInStr( const char* msg )
{
fputs( msg, stdout ); fflush( stdout );
return readLine( stdin );
}



/* accepts only positive (i.e. >= 0) valid int range of values ... */
int takeInValidPosInt( const char* prompt, int high )
{
char loc_buf[32], *tmpStr;
int good = 0, i = 0, len = 0, tmpInt = 0;

for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
{
tmpStr = takeInStrMaxLen( prompt, MAX_DIG_IN_INT );
len =  i = strlen( tmpStr );
good = ( i > 0 );
while( good && --i >= 0 )
{
if( !isdigit( tmpStr[i] ) ) { good = 0; break; }
}

if( good && len == MAX_DIG_IN_INT )
{
sprintf( loc_buf, "%d", INT_MAX );
if( strcmp( tmpStr, loc_buf ) > 0 ) good = 0;
}

if( good && tmpInt <= high )
{
tmpInt = atoi( tmpStr );
free( tmpStr );
break;
}
/* else ...*/
printf( "\nInvalid input! Integers only please, in valid range 0..%d\n",
high );
free( tmpStr );
}
return tmpInt;
}

/*  returns a valid int in range INT_MIN..INT_MAX */
int takeInValidMinMaxInt( const char* prompt, int myMin, int myMax )
{
char loc_buf[32];
int tmpInt;

for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
{
int good = 1, i = 0, len = 0, sign = 1;
char* tmp = takeInStrMaxLen( prompt, MAX_DIG_IN_INT+1 ); /* leave room


for + - */
char* tmpCpy = tmp;

if( tmp[0] == '+' ) ++tmp;
else if( tmp[0] == '-') { ++tmp; sign = -1; }

len = i = strlen( tmp );
good = ( i > 0 && i <= MAX_DIG_IN_INT );
while( good && --i >= 0 )
{
if( !isdigit( tmp[i] ) ) good = 0;
}

if( good && len == MAX_DIG_IN_INT )
{
if( sign == 1 )
{
sprintf( loc_buf, "%d", INT_MAX );
if( strcmp( tmp, loc_buf ) > 0 ) good = 0;
}
else
{
sprintf( loc_buf, "%d", INT_MIN );
if( strcmp( tmp, &loc_buf[1] ) > 0 ) good = 0;
}
}

if( good )
{
tmpInt = atoi( tmpCpy );
if( tmpInt >= myMin && tmpInt <= myMax )
{
free( tmpCpy );
break;
}
}
/* else ...*/
printf( "\nInvalid input! Integers please, only in range %d..%d\n",
myMin, myMax );
free( tmpCpy );
}
return tmpInt;
}

/*  returns a valid int in range INT_MIN..INT_MAX */
int takeInValidInt( const char* prompt )
{
char loc_buf[32];
int tmpInt;

for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
{
int good = 1, i = 0, len = 0, sign = 1;
char* tmp = takeInStrMaxLen( prompt, MAX_DIG_IN_INT+1 ); /* leave room


for + - */
char* tmpCpy = tmp;

if( tmp[0] == '+' ) ++tmp;
else if( tmp[0] == '-') { ++tmp; sign = -1; }

len = i = strlen( tmp );
good = ( i > 0 && i <= MAX_DIG_IN_INT );
while( good && --i >= 0 )
{
if( !isdigit( tmp[i] ) ) good = 0;
}

if( good && len == MAX_DIG_IN_INT )
{
if( sign == 1 )
{
sprintf( loc_buf, "%d", INT_MAX );
if( strcmp( tmp, loc_buf ) > 0 ) good = 0;
}
else
{
sprintf( loc_buf, "%d", INT_MIN );
if( strcmp( tmp, &loc_buf[1] ) > 0 ) good = 0;
}
}

if( good )
{
tmpInt = atoi( tmpCpy );
free( tmpCpy );
break;
}
/* else ...*/
printf( "\nInvalid input! Integers please, only in range %d..%d\n",
INT_MIN, INT_MAX );
free( tmpCpy );
}
return tmpInt;
}

#endif
Title: Re: C SOME UTILITY functions ...
Post by: David on May 29, 2013, 10:07:12 AM
Example of binary search of array ... recursive and non recursive ...

Code: [Select]
/* test_binarySearch_intAry.c */


#include <stdio.h>

/* recursive ... */
int rBinarySearch( const int a[], int low, int high, int target )
{
    int mid;

    if( high < low ) return -1; /* NOT found ... */

    mid = low + ( ( high - low ) >> 1 ); /*  ( low + hign ) / 2   */

    if( target < a[mid] ) return rBinarySearch( a, low, mid - 1, target );
    /* else if ... */
    if( target > a[mid] ) return rBinarySearch( a, mid + 1, high, target );
    /* else ... */
    return mid; /* FOUND at this index = mid */
}

/* iterative ...
   if multiple same target values ... finds index of first target value in ary */
int iBinarySearch( const int ary[], int low, int high, int target )
{
    while( low < high )
    {
        int mid = low + ( ( high - low ) >> 1 ); /*   ( low + hign ) / 2   */

        if( ary[mid] < target  ) low = mid + 1;
        else high = mid;
    }

    /* when reach here ... */
    if( high == low && target == ary[low] ) return low;
    /* else ... */
    return -1;
}


int main()
{
    int a[] = { 0, 2, 4, 6, 8 };
    int i, j, size = sizeof(a) / sizeof(int);

    for( i = a[0]; i <= a[size-1]; ++ i)
    {
        j = iBinarySearch( a, 0, size-1, i );
        if( j == -1 )
            printf( "%d was NOT found in array ...\n", i );
        else
        {
            printf( "%d WAS found in array at index %d...\n", i, j );
        }
    }

    printf( "\nPress 'Enter' to continue/exit ... " ); fflush( stdout );
    getchar() ;
    return 0;
}
Title: Re: C SOME UTILITY functions ...
Post by: David on May 31, 2013, 06:51:06 AM
Some CTIME ... today's date and time now ... utilities ... and a little test program follows ...



Code: [Select]
/* date_ctime.h */ /* 2013-05-30 */


#ifndef GET_DATE_H
#define GET_DATE_H

#ifndef OFFSET
#define OFFSET 1
#endif

/*
    Demo of C ctime to get date/time info ...
    (uses #include <time.h>)

    Demo of table lookup ... sscanf ... sprintf

    For BEGINNING COMPUTER PROGRAMMING using HLA, Python, C/C++
    http://developers-heaven.net/forum/index.php/topic,46.0.html
*/

#include <stdio.h>
#include <stdlib.h> /* atoi */
#include <string.h> /* strcmp, strncpy, strlen */
#include <time.h>   /* time_t now = time(0); ctime(&now) */


typedef struct
{
    int year;
    int month;
    int day;
    int dow; /* day of week range 0..6 */
   
    char time[6]; /* time 00:00..23:59 */
   
    char yearStr[5];
    char monthStr[10]; /* "September" + '\0' = 10 char's */
    char dowStr[10]; /* "Wednesday" + '\0' = 10 char's */
    char dummy;
   
} DateData ;

void printDateData( const DateData* dd )
{
printf( "%04d-%02d-%02d, day of week number is %d, and time now is %s\n",
dd->year, dd->month, dd->day, dd->dow, dd->time );
}


/* If passed in ... month = 9, offset = 1, returns 'September'... */
char* getMonthStr( int month )
{
    static char* months[] =
{
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
    "January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December", " "
} ;
    if( month > 0 && month < 13 ) return months[month-1+OFFSET*12];
    /* else ... */
    return months[24]; /*  returns " "  */
}
/* If passed in day =5, offset = 1, returns 'Friday' */
char* getWeekDayStr( int day ) /* day in range 0..6 */
{
static char* weekdays[] =
{
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
  "Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday", " "
} ;
    if( day >= 0 && day <= 6 )return weekdays[day+OFFSET*7];
    /* else ...*/
    return weekdays[14]; /*  returns " "  */
}

char* getMonthNumStr( const char* monthStr )
{
static char* monthNumStr[] =
{
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
    "01", "02", "03", "04", "05", "06",
    "07", "08", "09", "10", "11", "12", " "
} ;
int i;
for( i = 0; i < 12; ++i )
if( strcmp( monthNumStr[i], monthStr) == 0 )
return monthNumStr[i+12];
return monthNumStr[24];
}

char* getWeekDayNumStr( const char* dayStr )
{
static char* dayNumStr[] =
{
    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
    "01", "02", "03", "04", "05", "06", "07", " "
} ;
int i;
for( i = 0; i < 7; ++i )
if( strcmp( dayNumStr[i], dayStr) == 0 )
return dayNumStr[i+7];
return dayNumStr[14];
}


char* getDateNowStr( char dateNowStr[] ) /* must be 11 or more char's long */
{
    char dateTimeStr[25]; /* leave room for '\0' at end */
    char weekDayStr[4], monthStr[4], mDayNumStr[3], timeStr[9], yearStr[5];

    time_t now = time(0);
    memcpy( dateTimeStr, ctime(&now), 24 ); /* leave off '\n' char */
    dateTimeStr[24] = 0; /* so can print out as C string, if desired */

    /* Ok ... now we can parse the string dateTimeStr into 5 sub-strings */

    /* Fri Feb 12 16:22:24 2009 */
    sscanf( dateTimeStr, "%s %s %s %s %s",
            weekDayStr, monthStr, mDayNumStr, timeStr, yearStr );
    sprintf( dateNowStr, "%s-%s-%s", yearStr, getMonthNumStr( monthStr ), mDayNumStr );
   
    return dateNowStr;
}

char* getDateNowStrPlain( char dateNowStr[] ) /* must be 9 or more char's long */
{
    char dateTimeStr[25]; /* leave room for '\0' at end */
    char weekDayStr[4], monthStr[4], mDayNumStr[3], timeStr[9], yearStr[5];

    time_t now = time(0);
    memcpy( dateTimeStr, ctime(&now), 24 ); /* leave off '\n' char */
    dateTimeStr[24] = 0; /* so can print out as C string, if desired */

    /* Ok ... now we can parse the string dateTimeStr into 5 sub-strings ... */

    /* Fri Feb 12 16:22:24 2009 */
    sscanf( dateTimeStr, "%s %s %s %s %s",
            weekDayStr, monthStr, mDayNumStr, timeStr, yearStr );
    sprintf( dateNowStr, "%s%s%s", yearStr, getMonthNumStr( monthStr ), mDayNumStr );
    return dateNowStr;
}


void getNowDateData( DateData* dd )
{
char dateTimeStr[25]; /* leave room for '\0' at end */
    char weekDayStr[4], monthStr[4], mDayNumStr[3], timeStr[9], yearStr[5];

    time_t now = time(0);
    memcpy( dateTimeStr, ctime(&now), 24 ); /* leave off '\n' char */
    dateTimeStr[24] = 0; /* so can print out as C string, if desired */

    /* Ok ... now we can parse the string dateTimeStr into 5 sub-strings ... */

    /* Fri Feb 12 16:22:24 2009 */
    sscanf( dateTimeStr, "%s %s %s %s %s",
            weekDayStr, monthStr, mDayNumStr, timeStr, yearStr );
    /* sprintf( s, "%s%s%s", yearStr, getMonthNumStr( monthStr ), mDayNumStr ); */
   
    dd->day = atoi( mDayNumStr );
    dd->month = atoi( getMonthNumStr( monthStr ) );
    dd->year = atoi( yearStr );
    dd->dow = atoi( getWeekDayNumStr( weekDayStr ) );
    memcpy( dd->time, timeStr, 5 );
    dd->time[5] = 0;
   
strcpy( dd->dowStr, getWeekDayStr( dd->dow ) );
    strcpy( dd->monthStr, getMonthStr( dd->month ) );
    sprintf( dd->yearStr, "%04d", dd->year );
}

#endif


Now ... the test program ...

Code: [Select]
/* test_date_ctime.h.c */ /* 2013-05-30 */

/* #define OFFSET 0 */ /* for short form of month and day names */

#include "date_ctime.h"


int main()
{
char loc_buf[128];
DateData today;

getNowDateData( &today );
printDateData( &today );

printf( "getDateNowStr( loc_buf ) = %s\n", getDateNowStr( loc_buf ) );
printf( "getDateNowStrPlain( loc_buf ) = %s\n", getDateNowStrPlain( loc_buf ) );
printf( "%s %s %d, %d @ %s\n",
today.dowStr, today.monthStr, today.day, today.year, today.time );

printf( "\nPress 'Enter' to exit ... " ); fflush( stdout );
getchar();

return 0;
}
Title: Re: C SOME UTILITY functions ...
Post by: David on May 31, 2013, 10:33:18 AM
isValidDate ... isValidDOB ... inclusive days between two dates (first the test file then the new include .h file ... which also includes file date_ctime.h  ... and the test program needs to also include ... Cutilities.h ... so all together here, you will need all FOUR FILES in your working folder/directory before you compile this next 'test' file ...



Code: [Select]
/* test_isValidDate.h.c */  /* 2013-05-31 */

#include "isValidDate.h"

#include "Cutilities.h"




int main()
{
char locBuf[128], locBuf2[128], *date, *date2, *today;

int dayOfWeek = 0, iDaysBetween = 0;

do
{
for( ; ; )
{
date = takeInStr( "Enter valid date yyyymmdd : ", locBuf, sizeof(locBuf), 8 );
if( isValidDate( date ) ) break;
/* else ... */
printf( "\nTry again ... %s was NOT a valid date.\n", date );
}
printf( "\nYou took in date %s\n", date );
dayOfWeek = getDayOfWeek( date );
printf( "%s was on a %s\n", date, getWeekDayStr( dayOfWeek ) );

for( ; ; )
{
date2 = takeInStr( "\nEnter valid date yyyymmdd : ", locBuf2, sizeof(locBuf2), 8 );
if( isValidDate( date2 ) ) break;
/* else ... */
printf( "\nTry again ... %s was NOT a valid date.\n", date2 );
}
printf( "\nYou took in date %s\n", date2 );
dayOfWeek = getDayOfWeek( date2 );
printf( "%s is %s\n", date2, getWeekDayStr( dayOfWeek ) );

iDaysBetween = inclusiveDaysBetween( date, date2 );
printf( "\nInclusive days between %s and %s = %d\n", date, date2, iDaysBetween );

today  = getDateNowStrPlain( locBuf2 );
printf( "\nToday is %s\n", today );
dayOfWeek = getDayOfWeek( today );
printf( "%s was on a %s\n", today, getWeekDayStr(dayOfWeek ) );

iDaysBetween = inclusiveDaysBetween( date, today );
printf( "\nInclusive days between %s and %s = %d\n", date, today, iDaysBetween );

putchar( '\n' ) ;

for( ; ; )
{
date = takeInStr( "\nEnter valid dob yyyymmdd : ", locBuf, sizeof(locBuf), 8 );
if( isValidDOB( date ) ) break;
/* else ... */
printf( "\nTry again ... %s was NOT a valid date.\n", date );
}
printf( "\nYou took in date %s\n", date );
dayOfWeek = getDayOfWeek( date );
printf( "%s was on a %s\n", date, getWeekDayStr( dayOfWeek ) );

for( ; ; )
{
date2 = takeInStr( "\nEnter valid dob yyyymmdd : ", locBuf2, sizeof(locBuf2), 8 );
if( isValidDOB( date2 ) ) break;
/* else ... */
printf( "\nTry again ... %s was NOT a valid date.\n", date2 );
}
printf( "\nYou took in date %s\n", date2 );
dayOfWeek = getDayOfWeek( date2 );
printf( "%s was on a %s\n", date2, getWeekDayStr( dayOfWeek ) );

iDaysBetween = inclusiveDaysBetween( date, date2 );
printf( "\nInclusive days between %s and %s = %d\n", date, date2, iDaysBetween );

putchar( '\n' ) ;
}
while( more() );

return 0;
}


And the new include file ...

Code: [Select]
/* isValidDate.h */ /* 2013-05-31 */



/* needs stdlib.h ( atoi ), string.h ( strlen, strncpy )*/

#ifndef IS_VALID_DATE_H
#define IS_VALID_DATE_H

#include "date_ctime.h" /* includes stdio.h, stdlib.h, string.h, time.h */


typedef struct
{
int year;
int month;
int day;
} YMD ;

void initYMD( YMD* date )
{
char loc_buf[16];
getDateNowStrPlain( loc_buf );
date->day = atoi( loc_buf + 6 );

loc_buf[6] = 0;
date->month = atoi( loc_buf + 4 );

loc_buf[4] = 0;
date->year = atoi( loc_buf );
}

YMD getYMD( const char* plainDate )
{
char loc_buf[16];
YMD date;
strcpy( loc_buf, plainDate );

date.day = atoi( loc_buf + 6 );

loc_buf[6] = 0;
date.month = atoi( loc_buf + 4 );

loc_buf[4] = 0;
date.year = atoi( loc_buf );

return date;
}



/* forward declarations ... */

int isLeapYear( int y );
int daysInMonth( int m, int y );
int isValidDOB( const char* dob ); /* 20120526 ... must be 8 char's long */
int isValidDate( const char* test );

void nextDay( char date[] ); /* updates 8 char date to next day ... */
void prevDay( char date[] ); /* updates 8 char date to prev day ... */
int inclusiveDaysBetween( const char* date1, const char* date2 );

int getDayOfWeek( const char* date );



/* definitions ... */

int isLeapYear( int y )
{
    if( y % 4 != 0 ) return 0;
    if( y % 100 == 0 && y % 400 != 0 ) return 0;
    return 1;
}

int daysInMonth( int m, int y )
{   /* -------------------> jan feb mar apr may jun jul aug sep oct nov dec */
    int daysInMonth[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    int days = daysInMonth[m];
    if( m == 2 && isLeapYear( y )) ++days;
    return days;
}

int isValidDOB( const char* dob )
{
    /* char date[9]; */
    YMD dOfB, d;

    if( strlen( dob ) != 8 ) return 0;
   
    /* getDateNowStrPlain( date );
    d = getYMD( date ); */
    initYMD( &d );
   
    dOfB = getYMD( dob );

    if( dOfB.year < 1600 || dOfB.year > d.year )
        return 0; /* since not valid year here */
 
    if( dOfB.year < d.year )
    {
        if( dOfB.month < 1 || dOfB.month > 12 ) return 0; /* since not valid month */
    }
    else /* dOfB.y == d.y */
    {
        if(dOfB.month < 1 || dOfB.month > d.month ) return 0; /* since not valid month */
    }

    if( dOfB.year < d.year )
    {
        if( dOfB.year < 1 || dOfB.day > daysInMonth( dOfB.month, dOfB.year ) )
            return 0; /* since not valid day */
    }
    else /* y == yy */
    {
        if( dOfB.month < d.month )
        {
            if( dOfB.day < 1 || dOfB.day > daysInMonth( dOfB.month, dOfB.year ) )
                return 0; /* since not valid day */
        }
        else /* m == mm */
        {
            if( dOfB.day < 1 || dOfB.day > d.day )
                return 0; /* since not valid day */
        }
    }
   
    /* else ... if reach here ... must be valid date, so ... */
    return 1;   
}

int isValidDate( const char* test )
{
    char buffer[5] = { 0 };
    int y, m, d;

    if( strlen( test ) != 8 ) return 0;


    memcpy( buffer, test, 4 );
    y = atoi( buffer );
    if( y < 1600 ) return 0; /* since not valid year here ... */


    memcpy( buffer, test+4, 2 );
    buffer[2] = 0; /* 0 terminate ... */
    m = atoi( buffer );
    if(m < 1 || m > 12) return 0; /* since not valid month */


    d = atoi( test+6 );
    if( d < 1 || d > daysInMonth( m, y )) return 0; /* since not valid day */

    /* else ... if reach here ... must be valid date, so ... */
    return 1;
}

void nextDay( char* date )
{
    /* get year, month, day ... */
    YMD d = getYMD( date );

    ++d.day;
    if( d.day > daysInMonth( d.month, d.year ) )
    {
        d.day = 1;
        ++d.month;
        if( d.month > 12 )
        {
            d.month = 1;
            ++d.year;
        }
    }
    sprintf( date, "%04d%02d%02d", d.year, d.month, d.day );
}

void prevDay( char* date )
{
    /* get  d, m, y ... */
    YMD d = getYMD( date );

    --d.day;
    if( d.day < 1 )
    {
        --d.month;
        if( d.month < 1 )
        {
            --d.year;
            d.month = 12;
            d.day = 31;
        }
        else d.day = daysInMonth( d.month, d.year );
    }
    sprintf( date, "%04d%02d%02d", d.year, d.month, d.day );
}

int inclusiveDaysBetween( const char* date1, const char* date2 )
{
    char buf[9];
    int days = 1;
    if( strcmp( date1, date2 ) == 0 ) return 1;

    else if( strcmp( date1, date2 ) < 0 )
    {
        memcpy( buf, date1, 9 );
        while( strcmp( buf, date2 ) < 0 ) { ++days; nextDay( buf ); }
    }
    else
    {
        memcpy( buf, date1, 9 );
        while( strcmp( buf, date2 ) > 0 ) { ++days; prevDay( buf ); }
    }
    return days;
}


int getDayOfWeek( const char* date )
{
    if( isValidDate( date ) )
    {
        int daysDif;
        char today[9];
        DateData dd;
getNowDateData( &dd );
        sprintf( today, "%04d%02d%02d", dd.year, dd.month, dd.day );
        daysDif = inclusiveDaysBetween( date, today );
        --daysDif;

        /* return (7*daysDif + dd.dOfWeek-1-daysDif) % 7; */
        return (6*daysDif + dd.dow-1) % 7 ;
    }
    printf( "%s is NOT a valid date. Returning -1 ...\n", date );
    return -1; /* 0..6 */
}

#endif
Title: Re: C SOME UTILITY functions ...
Post by: David on May 31, 2013, 11:16:46 AM
* Doesn't use windows.h ....
* Uses a call to a NOT so well known library function ...
* strftime( bufferStr, bufsize, formatString, pointer_to_struc_tm_info )



Code: [Select]
/* dateTime1.c */ /* 2013-05-31 */

/*
* Doesn't use windows.h ....
* Uses a call to a NOT so well known library function ...
* strftime( bufferStr, bufsize, formatString, pointer_to_struc_tm_info )
*
* For BEGINNING COMPUTER PROGRAMMING using HLA, Python, C/C++
* http://developers-heaven.net/forum/index.php/topic,46.0.html
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main ()
{
char buffer [128];
    time_t rawtime;
struct tm* timeinfo;

    time( &rawtime );
    timeinfo = localtime( &rawtime ); /* to access LOCAL date/time info*/

    strftime( buffer, 128, "Time now is %I:%M %p", timeinfo );
    printf( "%s ...\n\n", buffer );

    strftime( buffer, 128, "%A %B %d, day %j of year %Y, %X %Z.", timeinfo );
    printf( "%s\n\n", buffer );

    strftime( buffer, 128, "%Y-%m-%d %X or if you like 'am/pm' it is %I:%M:%S %p", timeinfo );
    printf( "%s\n\n", buffer );

    strftime( buffer, 128, "%a %b %d, 20%y at %I:%M:%S %p", timeinfo );
    printf( "%s\n\n", buffer );

    /* Or ... get the 'bits' just the way you like ... */

    strftime( buffer, 128, "%A %B", timeinfo );
    printf( "%s", buffer ); /* print the fullDay fullMonth*/

    strftime( buffer, 128, "%d", timeinfo );
    printf( " %d, ", atoi(buffer) ); /* print the day number as an integer so NO leading '0' */

    strftime( buffer, 128, "%Y at %I:%M:%S %p", timeinfo );
    printf( "%s ", buffer ); /* print 'YYYY at hh:mm:ssAM/PM' */

    printf( "\n\nPress 'Enter' to continue ... " );
    getchar(); /* To keep Window open ... if needed. */
    return 0;
}

/*
%a    Abbreviated weekday name *                                               Thu
%A    Full weekday name *                                                 Thursday
%b    Abbreviated month name *                                                 Aug
%B    Full month name *                                                     August
%c    Date and time representation *                      Thu Aug 23 14:55:02 2001
%d    Day of the month (01-31)                                                  23
%H    Hour in 24h format (00-23)                                                14
%I    Hour in 12h format (01-12)                                                02
%j    Day of the year (001-366)                                                235
%m    Month as a decimal number (01-12)                                         08
%M    Minute (00-59)                                                            55
%p    AM or PM designation                                                      PM
%S    Second (00-61)                                                            02
%U    Week number with the first Sunday as the first day of week one (00-53)    33
%w    Weekday as a decimal number with Sunday as 0 (0-6)                         4
%W    Week number with the first Monday as the first day of week one (00-53)    34
%x    Date representation *                                               08/23/01
%X    Time representation *                                               14:55:02
%y    Year, last two digits (00-99)                                             01
%Y    Year                                                                    2001
%Z    Timezone name or abbreviation                                            CDT
%%    A % sign

    * The above specifiers whose description is marked
      with an asterisk (*) are locale-dependent.
*/




Code: [Select]
/* dateTime2.c */

#include <stdio.h>
#include <time.h>

#define SIZE_BUF 128
/*
    For BEGINNING COMPUTER PROGRAMMING using HLA, Python, C/C++
    http://developers-heaven.net/forum/index.php/topic,46.0.html
*/

int main()
{
    time_t val_time_t;
    struct tm* now;
    char buf[SIZE_BUF];

    /*  11:07:38 PM (Friday, February 19)*/
    char formatStr1[] = "%I:%M:%S %p (%A %B %d, %Y)";

    /*                 2010 050 07  5 NOTE: add 1 to j, add 1 to U */
    char formatStr2[] = "%Y %j %U %w";
    int year, dayNum, weekNum, dOfWeekNum;

    /* Get local date and time */
    val_time_t = time( NULL );
    now = localtime( &val_time_t );

    printf( "Default   : %s\n", ctime(&val_time_t) );
   
    printf
    (
        "Date/Time : %d-%02d-%02d %02d:%02d:%02d\n\n",
        now->tm_year+1900, now->tm_mon+1, now->tm_mday, /* year, month, day*/
        now->tm_hour, now->tm_min, now->tm_sec /* hours, minutes, seconds*/
    );
   
    fputs( "My format : ", stdout );
    /* using sscanf ... get int value for year, dayNum, weekNum, dOfWeekNum */
    strftime( buf, sizeof(buf), formatStr2, now ); /* use foramtStr2 ... */
    sscanf( buf, "%d %d %d %d", &year, &dayNum, &weekNum, &dOfWeekNum );
    printf("%d day %d week %d weekday %d ",
            year, dayNum, weekNum+1, dOfWeekNum+1);
    strftime( buf, sizeof(buf), formatStr1, now ); /* use formatStr1 ... */
    puts( buf );

    fputs( "\nPress 'Enter' to continue ... ", stdout );
    getchar();
    return 0;
}


/*
%a    Abbreviated weekday name *                                               Thu
%A    Full weekday name *                                                 Thursday
%b    Abbreviated month name *                                                 Aug
%B    Full month name *                                                     August
%c    Date and time representation *                      Thu Aug 23 14:55:02 2001
%d    Day of the month (01-31)                                                  23
%H    Hour in 24h format (00-23)                                                14
%I    Hour in 12h format (01-12)                                                02
%j    Day of the year (001-366)                                                235
%m    Month as a decimal number (01-12)                                         08
%M    Minute (00-59)                                                            55
%p    AM or PM designation                                                      PM
%S    Second (00-61)                                                            02
%U    Week number with the first Sunday as the first day of week one (00-53)    33
%w    Weekday as a decimal number with Sunday as 0 (0-6)                         4
%W    Week number with the first Monday as the first day of week one (00-53)    34
%x    Date representation *                                               08/23/01
%X    Time representation *                                               14:55:02
%y    Year, last two digits (00-99)                                             01
%Y    Year                                                                    2001
%Z    Timezone name or abbreviation                                            CDT
%%    A % sign

    * The above specifiers whose description is marked
      with an asterisk (*) are locale-dependent.
*/
Title: Re: C SOME UTILITY functions ...
Post by: David on May 31, 2013, 12:53:20 PM
/* findMinMaxAvgDynamicAry.c */


Code: [Select]
/* findMinMaxAvgDynamicAry.c */ /* this version 2013-06-08 */

/* error in cal of avg fixed here now ... */

/*
    C program to find minimum, maximum and average of an array of numbers ...
    (using here a dynamic array of doubles)
*/

#include <stdio.h>
#include <stdlib.h>

/* pass in ary and size ... and ref's to min, max and avg.. */
void getMinMaxAvg( const double[], int, double*, double*,  double* );



int main( void )
{
int i, size = 0, numGood = 0;
double* obs; /* 'obs' is type 'pointer to double', a var to hold an address */
double max, min, avg;

while( size <= 0 )
{
printf( "Please enter the desired number of observations : " );
scanf( "%d", &size );
while( getchar() != '\n' ) ; /* flush all chars in stdin stream */
if( size <= 0 )
printf( "Input error! ONLY POSITIVE integers valid here... \n" );
}

if( size > 10 )
{
printf( "Sorry, %d not valid here ... so changed to 'Max = 10'\n", size );
size = 10;
}

   
obs = (double*) malloc(sizeof(double) * size);
if( obs == NULL ) return -1; /* malloc failed above ... */

/* 
now obs holds the address of the start of memory
just allocated to hold size 'doubles'
*/

for( i = 0 ; i < size  ; )
{
printf( "Observation %03d : ", i+1 );
numGood = scanf( "%lf", &obs[i] ); /*  Note: 'lf' for correct input of doubles */
while( getchar() != '\n' ) ; /* flush all chars in stdin stream */
if( numGood != 1 ) continue;
++i;
}

printf( "\nYou entered ...\n\n" );
for( i = 0; i < size; ++i )
{
printf( "%03d : ", i+1 );
printf( "%+e\n", obs[i] ); /* Note: 'e' handles doubles and float */
}
   
/* get variables to hold info returned by 'ref' */

/* Note: obs below is alread an 'address' to the array of doubles */
/* pass 'addresses' to pointer variables */
getMinMaxAvg( obs, size, &min, &max, &avg );

printf( "\nThe info you desired is : \n\n" );
printf( "Min: %e  Max: %e  Avg: %e\n\n", min, max, avg );

free( obs );

fputs( "Press 'Enter' to continue/exit ... ", stdout ); fflush( stdout );
getchar();
return 0;
}

/* note .... where we are catching 'addresses' .... */
/*  ...  inside ... we have to use the value at that address by using *var   */
void getMinMaxAvg( const double obs[], int size,
double* min, double* max,  double* avg )
{
*min = *max = *avg = 0.0; /* initial all (handles empty array size 0) */

if( size )
{
int i = 0;
*min = *max = *avg = obs[0]; /* use this as the 'opening' value */
for( i = 1; i < size; ++i ) /* start at 1 since already used 0 above */
{
*avg += obs[i]; /* sum = sum + obs[i] */
if( obs[i] < *min ) *min = obs[i]; /* update as applies */
if( obs[i] > *max ) *max = obs[i];       
}
*avg /= size;
/* when we reach here, we have updated max, min and avg */
}
}



/* findMinMaxAvgCvec.c */  /* also uses file "readLine.h" and file "Cvec.h" linked below ... */

Code: [Select]
/* findMinMaxAvgCvec.c */  /* this version 2016-10-09 */


/*
C program to find minimum, maximum and average of an array of numbers ...
using here a Cvec of doubles
Note: Cvec is an emulation in C of the C++ vector container ...
Cvec provides a reusable and readily expandable dynamic array in C
*/


#include "readLine.h" /* re. myAssert & also includes ...takeInChar.
stdio.h, stdlib.h, string.h, ctype.h, etc... */

typedef struct myDoubles
{
double val;
} Rec ;

void clearRec( Rec* p )
{
/* NO dynamic memory to free here,
   so to compile without warning re. 'p' ...
   set ... */
p->val = 0;
}

/* after above def's of 'Rec' and 'freeVrec' ... can NOW ... */
#include "Cvec.h"

/* pass in ref's to cv, min, max and avg... */
void getMinMaxAvg( const Cvec*, double*, double*, double* );




int main( void )
{
int i = 0;
double max, min, avg;
Rec r;
Cvec cv;
initCvec( &cv ); /* MUST initial to work ok ... */
   
for( ; ;  )
{
printf( "Enter observation %03d : ", i+1 );
if( scanf( "%lf", &r.val ) == 1 && getchar() == '\n')
{
    if( tolower(takeInChar( "Ok to accept (y/n) ? " )) == 'y' )
    {
                ++i;
                push_backCvec( &cv, &r );
                if( tolower(takeInChar( "More (y/n) ? " )) == 'n' )  break;
            }
        }
        else
        {
            while( getchar() != '\n' ) ; /* flush all chars in stdin stream */
            printf( "\nInput not accepted ... \n" );
        }
}

printf( "\nYou entered ...\n\n" );
for( i = 0; i < cv.size; ++i )
{
printf( "%03d : ", i+1 );
/* Note: 'e' handles doubles and float */
printf( "%+e\n", cv.ary[i].val );
}
   
/* get variables to hold info returned by 'ref' */


/* pass in 'addresses' to pointer variables */
getMinMaxAvg( &cv, &min, &max, &avg );

printf( "\nThe info you desired is : \n\n" );
printf( "Min: %e  Max: %e  Avg: %e\n\n", min, max, avg );

clearCvec( &cv );

takeInChar( "Press 'Enter' to continue/exit ... " );
return 0;
}




/*  note .... 'when we are passing addresses' ....
    inside ... we have to take the value at that address by using *var   
*/
void getMinMaxAvg( const Cvec* cv, double* min, double* max,  double* avg )
{
*min = *max = *avg = 0.0; /* initial all (handles empty array size 0) */

if( cv->size )
{
int i = 0;
*min = *max = *avg = cv->ary[0].val; /* use this as the 'opening' value */
for( i = 1; i < cv->size; ++i ) /* start at 1 since already used 0 above */
{
*avg += cv->ary[i].val;
/* update as applies ... */
if( cv->ary[i].val < *min ) *min = cv->ary[i].val;
if( cv->ary[i].val > *max ) *max = cv->ary[i].val;       
}
*avg /= cv->size;
/* when we reach here, we have updated max, min and avg */
}
}



/* findMinMaxAvgClist.c */  /* also uses file "readLine.h" and file "Clist.h" linked below ... */

Code: [Select]
/* findMinMaxAvgClist.c */  /* this version 2016-10-09 */


/*
C program to find minimum, maximum and average of an array of numbers ...
using here a Clist of doubles
Note: Clist is an emulation in C of the C++ list container ...
Clist provides a reusable and readily expandable dynamic list in C
*/

#include "readLine.h" /* re. myAssert & also includes ...
stdio.h, stdlib.h, string.h, cttype.h, etc... */

typedef struct myDoubles
{
double val;
struct myDoubles* next;
} Node ;

typedef Node* pNode ;

void clearNode( pNode p )
{
/* NO dynamic memory to free here,
   so to compile without warning re. 'not using p' ...
   set ... */
p->val = 0;
}

/* after above def's of 'List', 'pList' and 'clearLrec' ... can NOW ... */
#include "Clist.h"

/* Note: passing in ref's to Clist, cv, min, max ... */
void getMinMaxAvg( const Clist*, double*, double*,  double* );



int main( void )
{
int i = 0, numGood = 0;
double max, min, avg;
pNode p;
Node r;
Clist cl;
initClist( &cl ); /* MUST initial to work ok ... */
   
for( ; ;  )
{
printf( "Enter observation %03d : ", i+1 );
numGood = scanf( "%lf", &r.val ); /* 'lf' for correct input of doubles */
while( getchar() != '\n' ) ; /* flush all chars in stdin stream */
if( numGood == 1 && tolower( takeInChar( "Ok to accept (y/n) ? " )) == 'y' )
{
++i;
push_backClist( &cl, &r );
if( tolower(takeInChar( "More (y/n) ? " )) == 'n' )  break;
}
else printf( "\nInput not accepted ... \n" );
}

printf( "\nYou entered ...\n\n" );
p = cl.start;
for( ; p != NULL; p = p->next  )
{
printf( "%03d : ", ++i );
/* Note: 'e' handles doubles and float */
printf( "%+e\n", p->val );
}

/* get variables to hold info returned by 'ref' */


/* pass in 'addresses' to pointer variables */
getMinMaxAvg( &cl, &min, &max, &avg );

printf( "\nThe info you desired is : \n\n" );
printf( "Min: %e  Max: %e  Avg: %e\n\n", min, max, avg );

clearClist( &cl );

fputs( "Press 'Enter' to continue/exit ... ", stdout ); fflush( stdout );
getchar();
return 0;
}




/*  note .... 'when we are passing addresses' ....
    inside ... we have to take the value at that address by using *var   
*/
void getMinMaxAvg( const Clist* cl, double* min, double* max,  double* avg )
{
*min = *max = *avg = 0.0; /* initial all (handles empty list size 0) */

if( cl->size )
{
pNode p = cl->start;
*min = *max = *avg = p->val; /* use this as the 'opening' value */
p = p->next;
for( ; p != NULL; p = p->next )
{
*avg += p->val;
/* update as applies ... */
if( p->val < *min ) *min = p->val;
if( p->val > *max ) *max = p->val;       
}
*avg /= cl->size;
/* when we reach here, we have updated max, min and avg */
}
}



And now the links to the include files needed above ...

readLine.h

http://developers-heaven.net/forum/index.php/topic,2580.msg2864.html#msg2864


Cvec.h

http://developers-heaven.net/forum/index.php/topic,2580.0.html


Clist.h

http://developers-heaven.net/forum/index.php/topic,2582.0.html
Title: Re: C SOME UTILITY functions ...
Post by: David on June 05, 2013, 06:54:40 PM
This next series of programs illustrates possible solutions to a fairly common student problem ... a grades management system ... and by the end of this series ... I hope you can see the ease of coding that comes when you already have at hand some utility functions in .h files that can readily be included to ease your C coding.

Firstly ... the hard slugging to code it all in one big file, which file will have to be spread over TWO pages here, since that ONE BIG file has too many bytes to fit within the max page size permitted here.

Note: needs to include file"takeIn_readLine_utilities.h" and file "readLine.h"

Code: [Select]
/* StudentGradesManagementList.c */  /* revised 2016-11-02 */

/* NOTE!
         Also needed here are include files:
         takeInLine.h
         and
         readLine.h

    C/C++ students may like to see ...
   
    http://developers-heaven.net/forum/index.php/topic,127.0.html
    http://developers-heaven.net/forum/index.php/topic,134.0.html
    http://developers-heaven.net/forum/index.php/topic,106.0.html
    http://developers-heaven.net/forum/index.php/topic,46.0.html
*/

/* Globals ... */

#include "takeInLine.h" /* also includes readLine.h */

#define header1 "Student GRADES MANAGEMENT SYSTEM"
#define header2 "1. (I)nitialize Student record list in RAM\n" \
                "2. (A)dd i.e. insert in order, by name, a NEW Student record\n" \
                "3. view/(D)elete a Student record\n" \
                "4. view/(E)dit a Student record\n" \
                "5. (S)how all Student records (as inserted BY NAME above)\n" \
                "6. (F)ile all Student records presently in RAM\n" \
                "7. (R)ead all Student records on file into RAM\n" \
                "8. set/change (P)assword\n" \
                "9. e(X)it"

#define FNAME "Studentinfo.txt"
#define FNAME_PW "StudentPW.txt"
#define MIN_PW_LEN 8
#define MAX_STR_LEN 23
#define MAX_STR_LEN_STR "23"
#define MAX_ID_NUM 9999


typedef struct myStudent
{
    int id;
    char* last;
    char* first;
    int test1;
    int test2;
    int assignment;
    int labtest;
    int finalexam;
    struct myStudent* next;
} Student ;

typedef Student* pStudent;


/* can use these global var's to keep function calls much simpler ... */
pStudent pHead = NULL;
int numStudents = 0; /* to hold 'the number of Student records in memory' ...*/
int fileFlag = 0;    /* fileFlag indicates 'the need to update the file' ... */


/* forward declarations */

pStudent pFindID( int );
void add();
void insert( pStudent );
void showAll();
void viewEdit();
void viewDelete();
void view( const pStudent ) ;
void edit( pStudent );
void delStudent( pStudent );
void delAll();
void init();
void scramble( char[] );
void unscramble( char[] );
void writeAllToFile();
void exitNowYes();
int writeFile();
int readFile();
int passWord();
int newPW();
int StudentCmp( const pStudent, const pStudent );

int showMenuGetChoice()
{
    puts( header1 );

    if( numStudents != 1 )
        printf( "Presently there are %d records.\n\n", numStudents );
    else
        puts( "Presently there is 1 record in RAM.\n" );

    puts( header2 );
    return takeInChar( "\nPlease enter your selection  : " );
}



int main() /* **************  main start **************** */
{
    passWord();

    numStudents = readFile();

    for( ; ; ) /* Loop forever ... until 'return' ... */
    {
        int choice = -1; /*  error flag */
        choice = showMenuGetChoice();
        /* printf("You picked %d ... \n", choice ); */
        switch( choice )
        {
            case '1': case 'i': case 'I': init(); break; /* out of 'switch' */
            case '2': case 'a': case 'A': add(); break;
            case '3': case 'd': case 'D': viewDelete(); break;
            case '4': case 'e': case 'E': viewEdit(); break;
            case '5': case 's': case 'S': showAll(); break;
            case '6': case 'f': case 'F': writeAllToFile(); break;
            case '7': case 'r': case 'R':
            {
                /* If any were read ... will update Global variable pHead */
                int readNum = readFile();
                if( readNum > 0 )
                    numStudents = readNum; /* update Global numStudents */
            }
            break;
            case '8': case 'p': case 'P': newPW(); break;
            case '9': case 'x': case 'X': exitNowYes(); break;
            default: puts("\nNot implemented yet ...");
       
        } /* end switch */
       
    } /* end for ... */
    return 0;

} /* ******************* main end *********************** */



/* Function definitions ... */

/* A function to compare two Student records to permit sorting ... */
int StudentCmp( const pStudent pS1, const pStudent pS2 )
{
    int compare = strcmp(pS1->last, pS2->last);
    if( compare == 0 )
        return strcmp(pS1->first, pS2->first);
    return compare;
}

/* Return a pointer to the Student if ID found in list; else return NULL */
pStudent pFindID( int id )
{
    pStudent p = pHead;
    while( p != NULL )
    {
        if( p->id == id )
            return p; /* id number entered was already used */

        /* Else ... get next p to compare */
        p = p->next;
    }

    /* If reach here ... then id number not in list so ... */
    return NULL;
}

void exitNowYes()
{
    int quit = takeInChar( "\nPress 'X' to eXit  ... " );
    if( quit=='x' || quit=='X' )
    {
        if( fileFlag )
            writeAllToFile();

        printf("\nPress 'Enter' to exit right now ... ");
        if( (quit = getchar()) == '\n' )
        {
            delAll();
            exit(0);
        }
        else
            while(quit != '\n') quit = getchar(); /* flush stdin ... */
    }
}

void add() /* ... and insert in the proper place in the list. */
{
    pStudent pS;
    int ID = takeInIntPosMax        ( "Enter ID          : ", MAX_ID_NUM );

    if( pFindID(ID) || ID <= 0  ) /* i.e. if pointer returned is NOT NULL,
the id IS used */
    {
        printf( "\nID %d is NOT available.\n", ID );
        return; /* Exit to showMenuGetChoice right now ... */
    }

    /* If program reaches here, the ID just entered is available to use. */
    pS = (pStudent) newMem( sizeof(Student) );
    pS->id = ID;

    pS->last  = takeInLineMaxLen    ( "Enter Last  Name  : ", MAX_STR_LEN );
    strToTitleCase( pS->last );
    pS->first = takeInLineMaxLen    ( "Enter First Name  : ", MAX_STR_LEN );
    strToTitleCase( pS->first );

    pS->test1 = takeInIntPosMax     ( "Enter Test1       : ", 100 );
    pS->test2 = takeInIntPosMax     ( "Enter Test2       : ", 100 );
    pS->labtest = takeInIntPosMax   ( "Enter Lab Test    : ", 100 );
    pS->assignment = takeInIntPosMax( "Enter Assignmemt  : ", 100 );
    pS->finalexam = takeInIntPosMax ( "Enter Final Exam  : ", 100 );

    view( pS );

    /* Set up link to this node */
    insert( pS );
}

/* insert in list in proper order of: last name, first name */
void insert( pStudent pS )
{
    /* Firstly, we can handle the case where 'this' should be the first element. */
    if( pHead == NULL || StudentCmp( pS, pHead ) < 0 )
    {
        /* So ... it now becomes the first element ... */
        pS->next = pHead; /* old pHead becomes 2nd in list ... */
        pHead = pS; /* and ... this pS ... becomes the head of the list */
    }
    else /* NOT first ... so search the linked list for the right spot */
    {
        pStudent prev = pHead; /* Get a working copy of pHead in prev */
        /* Start comparing with element AFTER 'q' ... i.e. the 'next in' ... */
        while( prev->next != NULL && StudentCmp( prev->next, pS ) < 0 )
            prev = prev->next; /* Traverse the list ... */
        /*
            Ok, insert after 'q' by relinking the pointers (similar to above)
            ( Includes inserting at end position ... where q->next == NULL )
        */
        pS->next = prev->next; /* Inserted 'pS' is linked to 'upstream element' */
        prev->next = pS;  /* Now 'prev' is linked to the inserted 'pS' element */
    }

    /* update global variables */
    ++ numStudents;
    fileFlag = 1;
}

void showAll()
{
    pStudent p = pHead;
    int c;

    if (pHead==NULL)
    {
        puts("\nNo records in memory at present.") ;
        return;
    }

    /* If reach here ... */

    while( p!=NULL )
    {
        view( p );
        c = takeInChar( "\nPress 'Enter' to continue ... "
                        "or enter 'A' to abort ... ");
        if( c == 'a' || c == 'A' )
            return;
        p = p->next;
    }
}

void viewEdit()
{
    int yes = 0;
    int ID = takeInIntPosMax( "Enter the id number to View/Edit : ",
                              MAX_ID_NUM );
    /* see if pointer exists, i.e. get value or NULL */
    pStudent p = pFindID( ID );
    if( p ) /* if pointer returned above was not NULL ... */
    {
        view( p );
        yes = takeInChar( "\nEdit (y/n) ? " );
        if( yes=='y' || yes=='Y' )
            edit( p );
    }
    else
        printf( "\nStudent with ID number %d not found.\n", ID );
}

void view( const pStudent pS )
{
    printf
    (
        "ID number  : %d\n"
        "Last Name  : %s\n"
        "First Name : %s\n"
        "Test 1     : %d\n"
        "Test 2     : %d\n"
        "Assignment : %d\n"
        "Lab Test   : %d\n"
        "Final Exam : %d\n",
        pS->id, pS->last, pS->first,
        pS->test1, pS->test2, pS->assignment,
        pS->labtest, pS->finalexam
    );
}

void edit( pStudent pS )
{
    int ID;
    int idTmp = pS->id; /* Firstly get a backup copy of this id ... */

    pS->id = -1; /* Now ... reset old id number to a dummy value ... */

    ID = takeInIntPosMax( "Edit ID          : ", MAX_ID_NUM );
    if( pFindID( ID ) ) /* i.e. if pointer returned is not NULL, this 'ID' IS USED */
    {
        printf( "\nid %d is NOT available.\n", ID );
        pS->id = idTmp; /* Restore the id since this pS was NOT  edited */
        return; /* Exit to showMenuGetChoice right now ... */
    }

    /* If reach hear ... */

    delStudent( pS );/* Delete old record ... etc */

    pS = ( pStudent) newMem( sizeof( Student ) ); /* get new memory for new record */
    pS->id = ID;

    pS->last = takeInLineMaxLen( "Edit Last Name   : ", MAX_STR_LEN );
    strToTitleCase( pS->last );
    pS->first = takeInLineMaxLen( "Edit First Name  : ", MAX_STR_LEN );
    strToTitleCase( pS->first );

    pS->test1 = takeInIntPosMax     ( "Edit Test1       : ", 100 );
    pS->test2  = takeInIntPosMax    ( "Edit Test2       : ", 100 );
    pS->assignment = takeInIntPosMax( "Edit Assignment  : ", 100 );
    pS->labtest = takeInIntPosMax   ( "Edit Lab Test    : ", 100 );
    pS->finalexam = takeInIntPosMax ( "Edit Final Exam  : ", 100 );

    insert( pS );
}

void viewDelete()
{
    pStudent p;
    int yes = 0, ID = 0;

    ID = takeInInt( "Enter the id number to View/Delete : " );

    p = pFindID( ID ); /* see if pointer exists; i.e. get value or NULL */
    if( p ) /* i.e. if pointer returned above was not NULL ... */
    {
        view( p );
        yes = takeInChar( "\nDelete (y/n) ? " );
        if( yes == 'y' || yes == 'Y' )
            delStudent( p );
    }
    else printf("\nStudent with ID number %d not found.\n", ID);
}

void delStudent( pStudent pS )
{
    /* handle special case of 'first in list' */
    if( pS == pHead )
    {
        pHead = pS->next;
        free( pS->first );
        free( pS->last );
        free( pS );
        /* update globals ... */
        --numStudents;
        fileFlag = 1;
        return;
    }

    /* else NOT first in list, so ... */
    if( numStudents > 1 )
    {
        pStudent prev = pHead; /* set p to this initial value to start loop */
        pStudent cur = pHead->next;
        /* now find the pointer to the previous record */
        while( cur != pS )
        {
            prev = cur; /* pp holds previous pointer value ... */
            cur = cur->next; /* set to next pointer in link list chain */
        }
        /*
            Now we have a pointer to the previous Student record, so ...
            we can now point that previous record to one past this pS record
        */
        prev->next = pS->next;
        /* Now free the memory for this record ... */
        free( pS->first );
        free( pS->last );
        free( pS);
        /* and update globals */
        --numStudents;
        fileFlag = 1;
    }
}

void delAll()
{
    while( pHead != NULL )
    {
        pStudent pNext = pHead->next; /* Get a pointer to the next record. */
        free( pHead->first );
        free( pHead->last );
        free( pHead );
        pHead = pNext; /* Update pHead ... */
    }

    /* Update globals ...  */
    /* pHead = NULL; */ /* Note was updated to NULL above */
    numStudents = 0;
    fileFlag = 1;
}

/* Note: calling delAll() here ... will re-set globals as above ... */
void init()
{
    if( pHead != NULL )
    {
        if( tolower( takeInChar( "\nDo you wish to overwrite the "
                                 "records in memory y/n ? " )) == 'y' )
            delAll(); /* re-sets globals ... */
        else
        {
            if( numStudents == 1 )
                puts( "1 Student Record was left intact in memory." );
            else
                printf( "%d Student Records were left intact in memory.\n",
                        numStudents );
        }
    }
    else puts( "\nThere were no records in memory to clear." );
}
Title: Re: C SOME UTILITY functions ...
Post by: David on June 05, 2013, 06:57:11 PM
File for ...

/* StudentGradesManagement.c */ /* revised 2016-11-02 */*/

continued on this page (since it wouldn't all fit into the one page above) ...

Code: [Select]
void scramble( char s[] )
{
    int i = 0;
    int code[] = {3,1,4,1,5,9,8,6,7,0,7,0,2,8,6,9,5,3,4,2};
    while( s[i]!=0 )
    {
        s[i] = (char) ((int)s[i] - code[i]);
        ++i;
    }
}

void unscramble( char s[] )
{
    int i = 0;
    int code[] = {3,1,4,1,5,9,8,6,7,0,7,0,2,8,6,9,5,3,4,2};
    while( s[i]!=0 )
    {
        s[i] = (char) ((int)s[i] + code[i]);
        ++i;
    }
}


int passWord()
{
    /*
        Get the password in the file, if it exists, into buffer2
        and compare it with the user entry in buffer1.
    */
    char* buffer1;
    char buffer2[MAX_STR_LEN+1];
    int attempts;

    int pwOK = 0;
    FILE* fp = fopen( FNAME_PW, "r" );

    if( !fp ) /* i.e. if file FNAME_PW doesn't exit ... */
    {
        pwOK = newPW(); /* get new password ...*/
        if( pwOK ) return 1; /* report this match of passwords back ...*/
    }
    else /* File FNAME_PW does exist ... so ... */
    {
        fscanf( fp, "%s", buffer2 );
        fclose( fp );
        unscramble( buffer2 );

        /* Now ... get password entered by user into a string in buffer1. */
        for( attempts = 0; attempts < 3; ++ attempts )
        {
            buffer1 = takeInLine( "Enter password: " );
            if( strcmp( buffer1, buffer2 ) == 0 ) /* If true ... passwords matched. */
            {
                puts( "Match!\n" );
                free( buffer1 );
                return 1; /* Report this match of passwords back ...*/
            }
            free( buffer1 );
        }
    }
    /* if reach here ...*/

    printf( "NO MATCH! ... Press 'Enter' to exit ... " );
    getchar();
    exit(1); /* Quit the program right now ... */
}

int newPW()
{
    FILE* fp;
    char* buffer1;
    char* buffer2;

    for( ; ; )
    {
        /* Get the new password into a string in buffer1. */
        buffer1 =  takeInLineMaxLen( "Enter the new password (8 to " MAX_STR_LEN_STR
                                     " characters): ", MAX_STR_LEN );
        if( strlen(buffer1) >= MIN_PW_LEN )
            break;

        printf("Your password must be at least %d characters ...\n", MIN_PW_LEN );
        free( buffer1 ); /* ... and try again ...*/
    }

    /*
        Get a 'verify copy' of the new password into buffer2
        and compare it with the password in buffer1.
    */
    buffer2 = takeInLine( "Enter the new password again: " );
    if(strcmp(buffer1, buffer2)==0) /* If true ... passwords matched. */
    {
        fp = fopen(FNAME_PW, "w");
        if(fp==NULL)
        {
            printf("Error opening file %s ... Press 'Enter' to exit ... ", FNAME_PW);
            free(buffer2);
            free(buffer1);
            getchar();
            exit(2);
        }
        else
        {
            puts( "Match!\n" );
            scramble(buffer1);
            fprintf( fp, "%s", buffer1 );
            fclose( fp );
            free(buffer2);
            free(buffer1);
            return 1; /* Report this match of passwords back ...*/
        }
    }

    /* If reach here ...*/

    printf( "NO MATCH! ... Press 'Enter' to exit ... " );
    free(buffer2);
    free(buffer1);
    getchar();
    exit(3); /* Quit the program right now ... */
}

/* -------------------------------------------------------*/


void writeAllToFile()
{
    if( !fileFlag ) return;

    if( numStudents == writeFile() )
    {
        if( numStudents > 0 )
        {
            if( numStudents == 1 )
                puts("\nThe 1 Student record was safely filed.");
            else
                printf
                (
                    "\nAll %d Student records safely filed.\n",
                    numStudents
                );
        }
        fileFlag = 0;
    }
    else
    {
        printf
        (
            "\nAn error occured while filing the Student records."
            "\nPlease see the programmer for help with the problem.\n"
            "\nExiting the program now.  Press 'Enter' to continue ... "
        );
        getchar(); /* Holds window open to show above message. */
        exit(0); /* Return error number to system. */
    }
}

int writeFile()
{
    int count; /* to track the records actually written to the file */
    FILE* fp;
    pStudent p = pHead;

    if( pHead==NULL )
    {
        puts("\nNo records available ... so NO records written to file.") ;
        return 0;
    }

    fp = fopen( FNAME, "w" );
    if( fp==NULL )
    {
        printf("\nError opening file %s.  Press 'Enter' to continue ... ", FNAME);
        getchar();
        return 0;
    }

    count = 0; /* to track the records actually written to the file */
    while( p!=NULL )
    {
        fprintf
        (
            fp,
            "%d\n"
            "%s\n"
            "%s\n"
            "%d\n"
            "%d\n"
            "%d\n"
            "%d\n"
            "%d\n",
            p->id, p->last, p->first,
            p->test1, p->test2, p->assignment,
            p->labtest, p->finalexam
        );

        ++count;
        p = p->next;
    }

    fclose( fp );
    return count; /* Number of records written. */
}

int readFile()
{
    int numRecs = 0;
    FILE* fin = fopen( FNAME, "r" );
    if( fin )
    {
        Student stud;
        char* line;
        int i = 0;
        while( ( line = readLine( fin ) ) )
        {
            ++i;
            switch( i )
            {
                case 1: stud.id= atof(line); free( line ); break;
                case 2: stud.last = line; break;
                case 3: stud.first = line; break;
                case 4: stud.test1 = atof(line); free( line ); break;
                case 5: stud.test2 = atof(line); free( line ); break;
                case 6: stud.assignment = atof(line); free( line ); break;
                case 7: stud.labtest = atof(line); free( line ); break;
                default: /* i.e. case 8 */
                {
                    pStudent p;
                    stud.finalexam = atof(line);
                    free( line );
                    p = (pStudent) newMem( sizeof( Student ) );
                    memcpy( p, &stud, sizeof( Student ) );
                    insert( p );
                    ++ numRecs;
                    i = 0;
                }
            }
        }
        fclose( fin );
        fileFlag = 0;
        return numRecs;
    }
    return 0;
}
Title: Re: C SOME UTILITY functions ...
Post by: David on June 05, 2013, 07:05:22 PM
Now ... a version that INCLUDES FILE "takeInLine.h"

http://developers-heaven.net/forum/index.php/topic,2580.msg3207.html#msg3207

AND SO ... uses readLine ...  THUS, YOU WILL NEED TO HAVE FILE readLine.h TO INCLUDE ALSO!

http://developers-heaven.net/forum/index.php/topic,2580.msg2864.html#msg2864


Code: [Select]
/* StudentGradesManagementList.c */ /* revised 2013-07-11 */


#include "takeIn_readLine_utilities.h" /* revised 2013-07-11 */


/*
    C/C++ students may like to see ...
   
    http://developers-heaven.net/forum/index.php/topic,127.0.html
    http://developers-heaven.net/forum/index.php/topic,134.0.html
    http://developers-heaven.net/forum/index.php/topic,106.0.html
    http://developers-heaven.net/forum/index.php/topic,46.0.html
*/

/* Globals ... */

#define header1 "Student GRADES MANAGEMENT SYSTEM"
#define header2 "1. (I)nitialize Student record list in RAM\n" \
                "2. (A)dd i.e. insert in order, by name, a NEW Student record\n" \
                "3. view/(D)elete a Student record\n" \
                "4. view/(E)dit a Student record\n" \
                "5. (S)how all Student records (as inserted BY NAME above)\n" \
                "6. (F)ile all Student records presently in RAM\n" \
                "7. (R)ead all Student records on file into RAM\n" \
                "8. set/change (P)assword\n" \
                "9. e(X)it"
               
#define FNAME "Studentinfo.txt"
#define FNAME_PW "StudentPW.txt"
#define MIN_PW_LEN 8
#define MAX_STR_LEN 23
#define MAX_STR_LEN_STR "23"

#define sortRead 1

typedef struct myStudent
{
    int id;
    char* last;
    char* first;
    float test1;
    float test2;
    float assignment;
    float labtest;
    float finalexam;
    struct myStudent* next;
   
} Student ;

typedef Student* pStudent;

/* can use these global var's to keep function calls much simpler ... */
pStudent phead = NULL;
int numStudents = 0; /* to hold 'the number of Student records in memory' ...*/
int pwOK = 0;        /* to hold 'the password was OK' flag; 0=false & 1=true */
int fileFlag = 0;    /* fileFlag indicates 'the need to update the file' ... */

typedef struct
{
pStudent phead;
int numStudents; /* to hold 'the number of Student records in memory' ...*/
int pwOK; /* to hold 'the password was OK' flag; 0=false & 1=true */
int fileFlag; /* fileFlag indicates 'the need to update the file' ... */
} List;

void initList( List* myLst )
{
myLst->phead = NULL;
myLst->numStudents = 0;
myLst->pwOK = 0;
myLst->fileFlag = 0;
}

/* forward declarations */

pStudent pFindID( int id );
/* char* newCopy( char* str ); */
void add();
void insert( pStudent pS );
void flushStdin();
void showAll();
void viewEdit();
void viewDel();
void view( const pStudent pS) ;
void edit(pStudent pS);
void del(pStudent pS);
void delAll();
void init();
void scramble( char s[] );
void unscramble( char s[] );
void writeAllToFile();
void exitNowYes();
int writeFile();
int readFile();
int passWord();
int newPW();
int StudentCmp( pStudent pS1, pStudent pS2 );



int showMemuGetChoice()
{
    puts( header1 );
   
    if( numStudents != 1 )
printf( "Presently there are %d records.\n\n", numStudents );
    else
puts( "Presently there is 1 record in RAM.\n" );

    puts( header2 );
    return takeInChar( "\nPlease enter your selection  : " );
}




int main() /* main start * * * * * * * * * * * * * * * * * * * * * * * * * * */
{   
    int choice, readNum;
    List myLst;
    initList( & myLst );
   
    pwOK = passWord();
    myLst.pwOK = pwOK;
   
    numStudents = readFile();
    myLst.numStudents = numStudents;
   
    for( ; ; ) /* Loop forever ... until 'return' ... */
    {
        if( !pwOK )
            pwOK = passWord();
       
        choice = -1; /*  error flag */
        choice = showMemuGetChoice();
        /* printf("You picked %d ... \n", choice ); */
        switch( choice )
        {
            case '1': case 'i': case 'I': init(); break; /* out of 'switch' */
            case '2': case 'a': case 'A': add();  break;
            case '3': case 'd': case 'D': viewDel(); break;
            case '4': case 'e': case 'E': viewEdit(); break;
            case '5': case 's': case 'S': showAll(); break;
            case '6': case 'f': case 'F': writeAllToFile(); break;
            case '7': case 'r': case 'R':
            {
                /* If any were read ... will update Global variable phead */
                readNum = readFile();
                if( readNum > 0 )
                    numStudents = readNum; /* update Global numStudents */
            }
            break;
            case '8': case 'p': case 'P': pwOK = newPW(); break;
            case '9': case 'x': case 'X': exitNowYes(); break;
            default: puts("\nNot implemented yet ...");
        } /* end switch */
    } /* end for ... */
    return 0;
   
} /* main end * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */





/* Function definitions ... */


/* Return a pointer to the Student if ID found in list; else return NULL */
pStudent pFindID( int id )
{
    pStudent p = phead;
    if( p==NULL )
        return NULL; /* List empty ... so all id numbers are available */
   
    while( p != NULL )
    {
        if( p->id == id )
            return p; /* id number entered was already used */

        /* Else ... get next p to compare */
        p = p->next;
    } 
       
    /* If reach here ... then id number not in list so ... */
    return NULL;
}


void flushStdin()
{
    while( getchar() != '\n' );
}

void exitNowYes()
{
    int c, quit;
   
    printf("\nPress 'X' to eXit  ... ");
    c = quit = getchar();
    while(c != '\n') c=getchar(); /* flush stdin ... */
    if( quit=='x' || quit=='X' )
    {
        if( fileFlag )
            writeAllToFile();
           
        printf("\nPress 'Enter' to exit right now ... ");
        if( (c=getchar()) == '\n' )
            exit(0);
        else
            while(c != '\n') c=getchar(); /* flush stdin ... */
    }
}

void add() /* ... and insert in the proper place in the list. */
{
pStudent pS;
int ID = takeInValidInt( "Enter ID          :  " );

if( pFindID(ID) || ID <= 0  ) /* i.e. if pointer returned is NOT NULL,
the id IS used */
{
printf( "\nID %d is NOT available.\n", ID );
return; /* Exit to showMemuGetChoice right now ... */
}

/* If program reaches here, the ID just entered is available to use. */
pS = (pStudent) malloc( sizeof(Student) );
myAssert( ( pS != NULL ), "\nmalloc failed in add student ... \n" );

pS->id = ID;

pS->last  = takeInStrMaxLen         ( "Enter Last  Name  :  ", 20 );
pS->first = takeInStrMaxLen         ( "Enter First Name  :  ", 20 );

pS->test1 = takeInValidMinMaxInt    ( "Enter Test1       : ", 0, 100 );
pS->test2 = takeInValidMinMaxInt    ( "Enter Test2       : ", 0, 100 );
pS->labtest = takeInValidMinMaxInt  ( "Enter Assignmemt  : ", 0, 100 );
pS->finalexam = takeInValidMinMaxInt( "Enter Final Exam  : ", 0, 100 );

view( pS );

/* Set up link to this node */
insert( pS );
}

/* insert in list with last & first names in proper order */
void insert( pStudent pS )
{
    pStudent q;
   
    /* Firstly, we handle the case where 'this' should be the first element. */
    if(phead == NULL || StudentCmp(pS, phead) < 0)
    {
        /* So ... it now becomes the first element ... */
        pS->next = phead; /* old phead becomes 2nd in list ... */
        phead = pS; /* and ... this pS ... becomes the head of the list */
    }
    else /* If here ... search the linked list for the right location ... */
    {
        q = phead; /* Get a working copy of phead in q */
        /* Start comparing with element AFTER 'q' ... i.e. the 'next in' ... */
        while(q->next != NULL && StudentCmp(q->next, pS) < 0)
        {
            q = q->next; /* Traverse the list ... */
        }
        /*
            Ok, insert after 'q' by relinking the pointers (similar to above)
            ( Includes inserting at end position ... where q->next == NULL )
        */
        pS->next = q->next; /* Inserted 'pS' is linked to 'upstream element' */
        q->next = pS;  /* Now 'q' is updated to link to the new 'pS' element */
    }
   
    /* Update global variables. */
    ++numStudents;
    fileFlag = 1;
}

void showAll()
{
    pStudent p = phead;
    int c;

    if (phead==NULL)
    {
        puts("\nNo records in memory at present.") ;
        return;
    }
   
    /* If reach here ... */
   
    while( p!=NULL )
    {
        view( p );
        printf("\nPress 'Enter' to continue ... or enter 'A' to abort ... ");
        if( (c=getchar()) == 'a' || c == 'A' )
        {
            flushStdin();
            return;
        }
        while(c != '\n') c=getchar(); /* flush stdin ... */
        p = p->next;
    }
}

void viewEdit()
{
    int yes = 0, ID = 0;
    pStudent p;
   
    printf("Enter the id number to View/Edit : ");
    scanf("%d",&ID); flushStdin();
   
    p = pFindID(ID); /* See if pointer exists; i.e. get value or NULL */
    if( p )     /* i.e. if pointer returned above was not NULL ... */
    {
        view(p);
        printf("\nEdit (y/n) ? ");
        yes = getchar();
        if( yes=='y' || yes=='Y' )
        {
            while( yes!='\n' ) yes=getchar(); /* flush stdin */
            edit(p);
        }
        else while( yes!='\n' ) yes=getchar(); /* flush stdin */
    }
    else printf("\nStudent with ID number %d not found.\n", ID);
}

void view( const pStudent pS)
{
    printf
    (
        "ID number  : %d\n"
        "Last Name  : %s\n"
        "First Name : %s\n"
        "Test 1     : %.2f\n"
        "Test 2     : %.2f\n"       
        "Assignment : %.2f\n"
        "Lab Test   : %.2f\n"
        "Final Exam : %.2f\n",
        pS->id, pS->last, pS->first,
        pS->test1, pS->test2, pS->assignment,
        pS->labtest, pS->finalexam
    );   
}

void edit(pStudent pS)
{
    int ID;
    int idTmp = pS->id; /* Firstly get a backup copy of this id ... */
   
    pS->id = -1; /* Now ... reset old id number to a dummy value ... */

    printf("Edit ID          : ");
    ID = 0;
    scanf("%d", &ID); flushStdin();
   
    if( pFindID(ID) ) /* i.e. if pointer returned is not NULL, this 'ID' IS USED */
    {
        printf("\nid %d is NOT available.\n", ID );
        pS->id = idTmp; /* Restore the id since this pS was NOT  edited */
        return; /* Exit to showMemuGetChoice right now ... */
    }
   
    /* If reach hear ... */
   
    del(pS);/* Delete old record ... etc */
   
    pS = (pStudent) malloc(sizeof(Student)); /* get new memory for new record */
    pS->id = ID;
   
    printf("Edit Last Name   : ");
    pS->last = readLine(stdin);
    printf("Edit First Name  : ");
    pS->first = readLine(stdin);     

    printf("Edit Test1       : ");
    scanf( "%f", &pS->test1 );      flushStdin();       
    printf("Edit Test2       : ");
    scanf( "%f", &pS->test2 );      flushStdin(); 
    printf("Edit Assignment  : ");
    scanf( "%f", &pS->assignment ); flushStdin();       
    printf("Edit Lab Test    : ");
    scanf( "%f", &pS->labtest );    flushStdin();
    printf("Edit Final Exam  : ");
    scanf( "%f", &pS->finalexam );  flushStdin();
   
    insert( pS );
}

void viewDel()
{
    pStudent p;
    int yes = 0, ID = 0;

    printf("Enter the id number to View/Delete : ");
    scanf("%d",&ID); flushStdin();
   
    p = pFindID(ID); /* See if pointer exists; i.e. get value or NULL */
    if( p ) /* i.e. if pointer returned above was not NULL ... */
    {
        view(p);
        printf("\nDelete (y/n) ? ");
        yes = getchar();
        if( yes=='y' || yes=='Y' ) { del(p); fileFlag = 1; }
        while( yes!='\n' ) yes=getchar(); /* flush stdin */
    }
    else printf("\nStudent with ID number %d not found.\n", ID);
}

void del(pStudent pS)
{
    pStudent p,
             pp; /* to hold the pointer to the previous record */

    /* Handle special case of 'first in list' */
    if( pS==phead )
    {
        phead = pS->next;
        free( pS->first );
        free( pS->last );
        free( pS );
        --numStudents; /* update globals ... */
        fileFlag = 1;
        return;   
    }
   
    /* Else not first in list, so ... */
   
    p = phead; /* set p to this initial value to start loop */
   
    /* Now find the pointer to the previous record. */
    while( p != pS )
    {
        pp = p; /* pp holds previous pointer value ... */
        p = p->next; /* set to next pointer in link list chain */
    }
   
    /*
        Now we have a pointer to the previous Student record, so ...
        we can now point that previous record to one past this pS record           
    */
    pp->next = pS->next;
   
    /* Now free the memory for this record and update the globals ... */
    free( pS->first );
    free( pS->last );
    free( pS);
    --numStudents;
    fileFlag = 1;
}

void delAll()
{
    pStudent p = phead; /* Set p to this initial value to start loop */
    pStudent pNext;     /* To hold the pointer to the next record */
   
    while( p != NULL )
    {
        pNext = p->next; /* Get a pointer to the next record. */
        free( p->first );
        free( p->last );
        free( p );
        p = pNext; /* Update p ... */
    }
   
    /* Update globals ...  */
    phead = NULL;
    numStudents = 0;
    fileFlag = 0;
}

/* Note: calling delAll() here ... will re-set globals as above ... */
void init()
{
    if( phead != NULL )
    {
        if( tolower( takeInChar( "\nDo you wish to overwrite the "
"records in memory y/n ? " )) == 'y' )
            delAll(); /* re-sets globals ... */
        else
        {
            if( numStudents == 1 )
                puts( "1 Student Record was left intact in memory." );
            else
                printf( "%d Student Records were left intact in memory.\n",
                       numStudents );
        }
    }
    else puts( "\nThere were no records in memory to clear." );
}

/*  PLEASE NOTE!  THE REST OF CODE TO THIS PROGRAM IS ON THE FOLLOWING PAGE ... */
Title: Re: C SOME UTILITY functions ...
Post by: David on June 05, 2013, 07:07:21 PM
/* THE REST OF THE CODE FROM THE PROGRAM FILE "StudentGradesManagementList.c" ON THE ABOVE PAGE CONTINUES HERE ... */


Code: [Select]
void scramble( char s[] )
{
    int i = 0;
    int code[] = {3,1,4,1,5,9,8,6,7,0,7,0,2,8,6,9,5,3,4,2};
    while( s[i]!=0 ) { s[i] = (char) ((int)s[i] - code[i]); ++i; }
}

void unscramble( char s[] )
{   
    int i = 0;
    int code[] = {3,1,4,1,5,9,8,6,7,0,7,0,2,8,6,9,5,3,4,2};
    while( s[i]!=0 ) { s[i] = (char) ((int)s[i] + code[i]); ++i; }
}

void writeAllToFile()
{
    if( !fileFlag ) return;
   
    if( numStudents == writeFile() )
    {
        if( numStudents > 0 )
        {
            if( numStudents == 1 )
                puts("\nThe 1 Student record was safely filed.");
            else
                printf
                (
                    "\nAll %d Student records safely filed.\n",
                    numStudents
                );
        }   
    }
    else
    {
        printf
        (
            "\nAn error occured while filing the Student records."
            "\nPlease see the programmer for help with the problem.\n"
            "\nExiting the program now.  Press 'Enter' to continue ... "
        );
        flushStdin(); /* Holds window open to show above message. */
        exit(0); /* Return error number to system. */
    }   
}

int writeFile()
{   
    int count; /* to track the records actually written to the file */
    FILE* fp;
    pStudent p = phead;

    if( phead==NULL )
    {
        puts("\nNo records available ... so NO records written to file.") ;
        return 0;
    }
   
    fp = fopen( FNAME, "w" );
    if( fp==NULL )
    {
        printf("\nError opening file %s.  Press 'Enter' to continue ... ", FNAME);
        flushStdin();
        return 0;
    }
   
    count = 0; /* to track the records actually written to the file */
    while( p!=NULL )
    {
        fprintf
        (
            fp,
            "%d\n"
            "%s\n"
            "%s\n"
            "%.2f\n"
            "%.2f\n"       
            "%.2f\n"
            "%.2f\n"
            "%.2f\n",
            p->id, p->last, p->first,
            p->test1, p->test2, p->assignment,
            p->labtest, p->finalexam
        );
       
        ++count;
        p = p->next;
    }
   
    fclose( fp );
    fileFlag = 0;
    return count; /* Number of records written. */
}

int readFile()
{
    int count, ID;
    /* char buffer[MAX_STR_LEN+1]; */
    FILE *fp;

    pStudent pS;
#if !sortRead
    pStudent pp=NULL;
#endif

    fp = fopen( FNAME, "r" );
    if( fp==NULL )
    {
        printf
        (
            "\nError opening file %s.\n"
            "Perhaps it hasn't been created yet?\n"
            "Press 'Enter' to continue ... ",
            FNAME
        );
        flushStdin();
        return 0;
    }
   
    /* BUT!!! may need to delete any records in memory first. */
    init();
   
    /*
        NOTE: we need phead to be equal to NULL in the following ...
        to be permitted to set phead ... 
        to point to the first Student record in memory (read in from the file).
    */
    if( phead != NULL ) /* then exit with message ... */
    {
        if(numStudents==1)
            puts("\nThe 1 former Student record was left in memory.");
        else
            printf("\nThe %d former Student records were left in memory.\n", numStudents);
        return 0; /* So ...old count of Student records will NOT be updated. */
    }
   
    /* If the program reaches here ... then ... */
   
    count = 0;

    while(  fscanf( fp, "%d", &ID) != EOF  )
    {
        pS = (pStudent) malloc(sizeof(Student));
        pS->id = ID;
        #if 0
        //fscanf( fp, "%s", buffer );
        //pS->last = newCopy( buffer );
        #endif
        fgetc(fp); /* eats up the '\n' char left over from above 'ID read' */
        pS->last = readLine(fp);
       
        #if 0
        //fscanf( fp, "%s", buffer );
        //pS->first = newCopy( buffer );
        #endif
        pS->first = readLine(fp);

        fscanf( fp, "%f", &pS->test1 );     
        fscanf( fp, "%f", &pS->test2 );
        fscanf( fp, "%f", &pS->assignment );       
        fscanf( fp, "%f", &pS->labtest );
        fscanf( fp, "%f", &pS->finalexam );
#if !sortRead           
        if ( pp != NULL )   /* for 2nd and up records ...*/
            pp->next = pS;  /* now previous record points to this new one */
        else phead =pS;     /* first record only has base pointer */
           
        pS->next = 0; /* NULL terminate list ... */
        pp = pS; /* Keep a copy of address of this pS in pp for next while loop. */
#else
        insert( pS );
#endif     
        ++count;
        /* printf( "\nRecord number is %d\n", count ); */
    }
    fclose( fp );
    if(count==1)
        puts("\n1 record was read into memory from the disk file.");
    else
        printf("\n%d records were read into memory from the disk file.\n", count);
       
    fileFlag = 0;
    return count; /* Total number of Student records found in the file. */
}

int passWord()
{
    /*
        Get the password in the file, if it exists, into buffer2
        and compare it with the user entry in buffer1.
    */
    char* buffer1;
    char buffer2[MAX_STR_LEN+1];
    int attempts;

    int pwOK = 0;
    FILE* fp;
    fp = fopen(FNAME_PW, "r");

    if(fp==NULL) /* i.e. if file FNAME_PW doesn't exit ... */
    {
        pwOK = newPW(); /* get new password ...*/
        if( pwOK == 1 ) return 1; /* report this match of passwords back ...*/
    }
    else /* File FNAME_PW does exist ... so ... */
    {
        fscanf( fp, "%s", buffer2 );
        fclose( fp );
        unscramble( buffer2 );
       
        /* Now ... get password entered by user into a string in buffer1. */
        for( attempts=0; attempts<3; ++attempts )
        {
            printf("Enter password: ");
            /* //scanf( "%s", buffer1 ); flushStdin(); */
            buffer1 = readLine(stdin);
            if(strcmp(buffer1, buffer2)==0) /* If true ... passwords matched. */
            {
                puts( "Match!\n" );
                free( buffer1 );
                return 1; /* Report this match of passwords back ...*/
            }
            free( buffer1 );
        }
    }
    /* if reach here ...*/
   
    printf( "NO MATCH! ... Press 'Enter' to exit ... " );
    flushStdin();
    exit(1); /* Quit the program right now ... */
}

int newPW()
{
    FILE* fp;
    char* buffer1;
    char* buffer2;
   
    for( ; ; )
    {
/* Get the new password into a string in buffer1. */
buffer1 =  takeInStrMaxLen( "Enter the new password (8 to " MAX_STR_LEN_STR
" characters): ", MAX_STR_LEN );
if( strlen(buffer1) >= MIN_PW_LEN )
break;
       
        printf("Your password must be at least %d characters ...\n", MIN_PW_LEN );
        free( buffer1 ); /* ... and try again ...*/
    }
   
    /*
        Get a 'verify copy' of the new password into buffer2
        and compare it with the password in buffer1.
    */
    printf("Enter the new password again: ");
    buffer2 = readLine(stdin);
    if(strcmp(buffer1, buffer2)==0) /* If true ... passwords matched. */
    {
        fp = fopen(FNAME_PW, "w");
        if(fp==NULL)
        {
            printf("Error opening file %s ... Press 'Enter' to exit ... ", FNAME_PW);
            flushStdin();
            free(buffer2);
            free(buffer1);
            exit(2);
        }
        else
        {
            puts( "Match!\n" );
            scramble(buffer1);
            fprintf( fp, "%s", buffer1 );       
            fclose( fp );
            free(buffer2);
            free(buffer1);
            return 1; /* Report this match of passwords back ...*/
        }
    }
   
    /* If reach here ...*/
       
    printf( "NO MATCH! ... Press 'Enter' to exit ... " );
    flushStdin();
    free(buffer2);
    free(buffer1);
    exit(3); /* Quit the program right now ... */
}

/* A function to compare two Student records to permit sorting ... */
int StudentCmp( pStudent pS1, pStudent pS2 )
{
    int compare = strcmp(pS1->last, pS2->last);
    if ( compare == 0 )
        return strcmp(pS1->first, pS2->first);
   
    return compare;
}
Title: Re: C SOME UTILITY functions ...
Post by: David on June 05, 2013, 07:20:15 PM
Here ... the Student List code is split off into its own separate file ...

"Student_List.h "

which file, needs to be included in the program

"StudentGradesManagementList2.c"

that follows on the next page ...

Code: [Select]
/* Student_List.h */  /* 2016-11-02 */


#ifndef STUDENT_LIST_H
#define STUDENT_LIST_H


/* only myAssert (and includes) from readLine.h used here,
   but other stuff used in 'main' */
#include "takeInLine.h"


typedef struct myStudent
{
    int id;
    char* last;
    char* first;
    float test1;
    float test2;
    float assignment;
    float labtest;
    float finalexam;
    struct myStudent* next;

} Student ;

typedef Student* pStudent;

void clearStudent( pStudent cur )
{
    free( cur->first );
    free( cur->last );
}

void showStudent( const pStudent pS )
{
    printf
    (
        "ID number  : %d\n"
        "Last Name  : %s\n"
        "First Name : %s\n"
        "Test 1     : %.2f\n"
        "Test 2     : %.2f\n"
        "Assignment : %.2f\n"
        "Lab Test   : %.2f\n"
        "Final Exam : %.2f\n",
        pS->id, pS->last, pS->first,
        pS->test1, pS->test2, pS->assignment,
        pS->labtest, pS->finalexam
    );
}


/* A function to compare two Student records to permit sorting ... */
int StudentCmp( const pStudent pS1, const pStudent pS2 )
{
    int compare = strcmp( pS1->last, pS2->last );
    if ( compare == 0 )
        return strcmp( pS1->first, pS2->first) ;
    return compare;
}




typedef struct
{
    pStudent head;
    pStudent tail;
    int size; /* to hold 'the number of Student records in memory' ...*/
    int pwOK; /* to hold 'the password was OK' flag; 0=false & 1=true */
    int fileFlag; /* fileFlag indicates 'the need to update the file' ... */
} List;

void initList( List* myLst )
{
    myLst->head = NULL;
    myLst->tail = NULL;
    myLst->size = 0;
    myLst->pwOK = 0;
    myLst->fileFlag = 0;
}

void clearList( List* lst )
{
    pStudent cur = lst->head;
    for( ; cur != NULL; cur = lst->head  )
    {
        lst->head = cur->next;
        clearStudent( cur );
        free( cur );
    }
    initList( lst );
}

void push_backList( List* lst, Student* stud )
{
    Student* p = (Student*) malloc( sizeof(Student) );
    if( p == NULL )
    {
        clearList( lst );
        myAssert( 0, "Error: malloc failed in push_back..." );
    }

    /* now add in ALL new dat ... (assuming next pointer is last of dat) */
    memcpy( p, stud, sizeof(Student)-sizeof(pStudent) ); /* sizeof(any_pointer) is ok */
    /* and set pointers to next ... and start ...*/

    p->next = NULL;
    ++ lst->size;
    if( lst->size > 1 )
    {
        lst->tail->next = p;
        lst->tail = p;
    }
    else
        lst->head = lst->tail = p;
}

/* insertList in list with last & first names in proper order */
void insertList( List* lst, pStudent pS )
{
    pStudent q, phead = lst->head;

    /* 1st, handle the more probable case where 'this' is NOT the first element */
    if( phead && StudentCmp( pS, phead ) >= 0 )
    {
        /* If here ... search the linked list for the right location */

        q = phead; /* Get a working copy of phead in q */

        /* Start comparing with element AFTER 'q' ... i.e. the 'next in' ... */
        while( q->next != NULL && StudentCmp( q->next, pS) <= 0 )
        {
            q = q->next; /* Traverse the list ... */
        }
        /*
        Ok, insertList after 'q' by relinking the pointers (similar to above)
        ( Includes inserting at end position ... where q->next == NULL )
        */
        pS->next = q->next; /* Inserted 'pS' is linked to 'upstream element' */
        q->next = pS;  /* Now 'q' is updated to link to the new 'pS' element */

        if( pS->next == NULL ) lst->tail = pS;
    }
    else /* Yeah ... the first element ... */
    {
        pS->next = phead; /* old phead becomes 2nd in list ... */
        lst->head = pS; /* and ... this pS ... becomes the head of the list */
        if( !lst->size ) lst->tail = pS;
    }

    /* Update List variables... */
    ++lst->size;
    lst->fileFlag = 1;
}

/* Return a pointer to the Student if ID found in list; else return NULL */
pStudent pFindID( const List* lst, int id )
{
    pStudent p = lst->head;

    while( p != NULL )
    {
        if( p->id == id )
            return p; /* id number entered was already used */

        /* Else ... get next p to compare */
        p = p->next;
    }

    /* If reach here ... then id number not in list so ... */
    return NULL;
}

void delList( List* lst, pStudent pS )
{
    pStudent p,
             pp; /* to hold the pointer to the previous record */

    /* Handle special case of 'first in list' */
    if( pS == lst->head )
    {
        lst->head = pS->next;
        clearStudent( pS );
        free( pS );
        -- lst->size;
        if( lst->size == 0 ) lst->tail = NULL;
        lst->fileFlag = 1;
        return;
    }

    /* Else not first in list, so ... */

    p = lst->head; /* set p to this initial value to start loop */

    /* Now find the pointer to the previous record. */
    while( p != pS )
    {
        pp = p; /* pp holds previous pointer value ... */
        p = p->next; /* set to next pointer in link list chain */
    }

    /*
        Now we have a pointer to the previous Student record, so ...
        we can now point that previous record to one past this pS record
    */
    pp->next = pS->next;
    if( pp->next == NULL ) lst->tail = pp;

    /* Now free the memory for this record and update the list variables */
    clearStudent( pS );
    free( pS);
    -- lst->size;
    lst->fileFlag = 1;
}

#endif

CLICK ON 2 in lower left corner here to go to the next pages ...
Title: Re: C SOME UTILITY functions ...
Post by: David on June 05, 2013, 07:24:35 PM
This version of the program uses the file ...

"Student_List.h"

found above ...

It also needs file ...

"takeInLine.h" found at ...

http://developers-heaven.net/forum/index.php/topic,2580.msg3207.html#msg3207

and file "readLine.h" found at ...

http://developers-heaven.net/forum/index.php/topic,2580.msg2864.html#msg2864

Note also, the file "StudentGradesManagementList2.c ", NOW ALL FITS into ONE PAGE here :)

Code: [Select]
/* StudentGradesManagementList2.c */  /* revised 2016-11-02 */

/*
    C/C++ students may like to see ...
    http://developers-heaven.net/forum/index.php/topic,127.0.html
    http://developers-heaven.net/forum/index.php/topic,134.0.html
    http://developers-heaven.net/forum/index.php/topic,106.0.html
    http://developers-heaven.net/forum/index.php/topic,46.0.html
*/

#include "Student_List.h" /* includes takeInLine.h that includes readLine.h etc... */


#define header1 "Student GRADES MANAGEMENT SYSTEM"
#define header2 \
    "1. (I)nitialize (i.e. CLEAR) Student record list in RAM\n" \
    "2. (A)dd i.e. INSERT into LIST inorder by name, a NEW Student record.\n" \
    "3. view/(D)elete a Student record\n" \
    "4. view/(E)dit a Student record\n" \
    "5. (S)how all Student records (as inserted BY NAME above)\n" \
    "6. (F)ile all Student records presently in RAM\n" \
    "7. (R)ead all Student records on file into RAM\n" \
    "8. set/change (P)assword\n" \
    "9. e(X)it"

#define FNAME "Studentinfo.txt"
#define FNAME_PW "StudentPW.txt"
#define MIN_PW_LEN 8
#define MIN_PW_LEN_STR "8"
#define MAX_STR_LEN 23
#define MAX_STR_LEN_STR "23"


int showMenuGetChoice( List* lst ) ;
void initList2ndCheck( List* lst ) ;
int fillFromFile( List* lst ) ;
void showAll( const List* lst ) ;
void add( List* lst ) ;

void viewDel( List* lst  );

void editStudent( List* lst, pStudent old_pS );
void viewEdit( List* lst );

int writeFile( List* lst );
void writeAllToFile( List* lst );
int exitNowYesNo( List* lst );

void scramble( char s[] );
void unscramble( char s[] );

int passWord( List* lst );
int newPW( List* lst );



int main() /* ************* BEGIN MAIN ****************** */
{
    int done = 0;
    List myLst;

    initList( &myLst );

    passWord( &myLst );

    if( fillFromFile( &myLst ) )
    {
        if( myLst.size != 1  )
            printf("There were %d records read from file ...\n", myLst.size );
        else
            printf("There was %d record read from file ...\n", myLst.size );
        showAll( &myLst );
    }
    else
    {
        printf( "There was some problem opening file %s ... \n"
                "perhaps it doesn't exist yet?\n", FNAME );
    }

    while( !done )
    {
        switch(  showMenuGetChoice( &myLst ) )
        {
            case '1' : case 'i' : case 'I' : initList2ndCheck( &myLst ); break;
            case '2' : case 'a' : case 'A' : add( &myLst ); break;
            case '3' : case 'd' : case 'D' : viewDel( &myLst ); break;
            case '4' : case 'e' : case 'E' : viewEdit( &myLst ); break;
            case '5' : case 's' : case 'S' : showAll( &myLst ); break;
            case '6' : case 'f' : case 'F' : writeAllToFile( &myLst ); break;

            case '7': case 'r': case 'R':
                if( myLst.size )
                {
                    if( tolower( takeInChar( "Do you really want "
                                             "to over-ride present memory? "
                                             "(y/n) ? " )) == 'y' )
                    {
                        clearList( &myLst );

                        if( fillFromFile( &myLst ) )
                            printf( "\n%d records were read in from file %s\n",
                                    myLst.size, FNAME );
                        else printf( "\nThere was a problem opening file %s\n",
                                         FNAME );
                    }
                    else printf( "\nOver-ride aborted ... \n" );
                }
                else
                {
                    if( fillFromFile( &myLst ) )
                        printf( "\n%d records were read in from file %s\n",
                                myLst.size, FNAME );
                    else printf( "\nThere was a problem opening file %s\n",
                                     FNAME );
                }
                break;
            case '9' : case 'X' : case 'x' : done = exitNowYesNo( &myLst ); break;
            case '8' : case 'p' : case 'P' : newPW( &myLst ); break;
            default : printf( "\nNOT implemented here yet ...\n" );
           
        } /* end switch */
       
    } /* end while ! done */

    clearList( &myLst );
    return 0;
   
} /* ******************* END MAIN *********************** */





int showMenuGetChoice( List* lst )
{
    puts( header1 );

    if( lst->size != 1 )
        printf( "Presently there are %d records.\n\n", lst->size );
    else
        puts( "Presently there is 1 record in RAM.\n" );

    puts( header2 );
    return takeInChar( "\nPlease enter your selection  : " );
}


void initList2ndCheck( List* lst )
{
    pStudent phead = lst->head;

    if( phead != NULL )
    {
        if( tolower( takeInChar( "\nDo you wish to overwrite the "
                                 "records in memory y/n ? " )) == 'y' )
            clearList( lst );
        else
        {
            if( lst->size == 1 )
                puts( "1 Student Record was left intact in memory." );
            else
                printf( "%d Student Records were left intact in memory.\n",
                        lst->size );
        }
    }
    else puts( "\nThere were no records in memory to clear." );
}


int fillFromFile( List* lst )
{
    FILE* fin = fopen( FNAME, "r" );
    if( fin )
    {
        Student stud;
        char* line;
        int i = 0;
        while( ( line = readLine( fin ) ) )
        {
            ++i;
            if( i == 1 )
            {
                stud.id= atof(line);
                free( line );
            }
            else if( i == 2 ) stud.last = line;
            else if( i == 3 ) stud.first = line;
            else if( i == 4 )
            {
                stud.test1 = atof(line);
                free( line );
            }
            else if( i == 5 )
            {
                stud.test2 = atof(line);
                free( line );
            }
            else if( i == 6 )
            {
                stud.assignment = atof(line);
                free( line );
            }
            else if( i == 7 )
            {
                stud.labtest = atof(line);
                free( line );
            }
            else
            {
                stud.finalexam = atof(line);
                free( line );
                push_backList( lst, &stud );
                i = 0;
            }
        }
        fclose( fin );
        lst->fileFlag = 0;
        return 1;
    }
    return 0;
}

void showAll( const List* lst )
{
    pStudent p = lst->head;

    if( p == NULL )
    {
        puts("\nNo records in memory at present.") ;
        return;
    }

    /* If reach here ... */

    while( p != NULL )
    {
        showStudent( p );
        if( tolower( takeInChar( "\nPress 'Enter' to continue "
                                 "or enter 'A' to abort: " )) == 'a' ) return;
        p = p->next;
    }
}

void add( List* lst ) /* ... and insertList in the proper place in the list */
{
    pStudent pS;
    int ID = takeInIntPosMax( "Enter ID          : ", INT_MAX );

    if( pFindID( lst, ID ) || ID <= 0  ) /* i.e. if pointer returned is NOT NULL, the ID IS used */
    {
        printf( "\n\n *** ID %d is NOT available *** \n\n\n", ID );
        return; /* Exit to showMemuGetChoice right now ... */
    }

    /* If program reaches here, the ID just entered is available to use. */
    pS = (pStudent) malloc( sizeof(Student) );
    myAssert( ( pS != NULL ), "\nmalloc failed in add student ... \n" );

    pS->id = ID;

    pS->last  = takeInLineMaxLen    ( "Enter Last  Name  : ", MAX_STR_LEN );
    strToTitleCase( pS->last);
    pS->first = takeInLineMaxLen    ( "Enter First Name  : ", MAX_STR_LEN );
    strToTitleCase( pS->first);

    pS->test1 = takeInIntPosMax     ( "Enter Test1       : ", 100 );
    pS->test2 = takeInIntPosMax     ( "Enter Test2       : ", 100 );
    pS->assignment = takeInIntPosMax( "Enter Assignmemt  : ", 100 );
    pS->labtest = takeInIntPosMax   ( "Enter Lab Test    : ", 100 );
    pS->finalexam = takeInIntPosMax ( "Enter Final Exam  : ", 100 );

    showStudent( pS );

    if( tolower( takeInChar( "Ok to add (y/n) ? 0" )) == 'y' )
        insertList( lst, pS );
    else
    {
        printf( "\nNot added ...\n" );
        clearStudent( pS );
    }
}

void viewDel( List* lst )
{
    int ID = takeInIntPosMax( "Enter the id number to View/Delete : " , INT_MAX );
    pStudent p = pFindID( lst, ID ); /* get pointer value or NULL */
    if( p ) /* i.e. if pointer returned above was not NULL ... */
    {
        showStudent( p );
        if( tolower( takeInChar( "\nDelete (y/n) ? " )) == 'y' )
            delList( lst, p) ;
    }
    else printf( "\nStudent with ID number %d not found.\n", ID );
}

void editStudent( List* lst, pStudent old_pS )
{
    pStudent pS;

    int idTmp = old_pS->id; /* Firstly get a backup copy of this id ... */

    int ID = takeInIntPosMax( "Enter EDITED ID          : ", INT_MAX );

    old_pS->id = -1; /* Now ... reset old id number to a dummy value ... */

    if( pFindID( lst, ID ) ) /* i.e. if pointer returned not NULL, this 'ID' IS USED */
    {
        printf( "\nid %d is NOT available.\n", ID );
        old_pS->id = idTmp; /* Restore the id since this pS was NOT  edited */
        return; /* Exit to showMemuGetChoice right now ... */
    }

    /* If reach hear ... insertList new pStudent in new memory with new data */

    pS = (pStudent) malloc( sizeof(Student) );
    myAssert( ( pS != NULL ), "\nmalloc failed in add student ... \n" );

    pS->id = ID;

    pS->last  = takeInLineMaxLen    ( "Enter EDITED Last  Name  : ",
                                         MAX_STR_LEN );
    strToTitleCase( pS->last);
    pS->first = takeInLineMaxLen    ( "Enter EDITED First Name  : ",
                                         MAX_STR_LEN );
    strToTitleCase( pS->first);

    pS->test1 = takeInIntPosMax     ( "Enter EDITED Test1       : ", 100 );
    pS->test2 = takeInIntPosMax     ( "Enter EDITED Test2       : ", 100 );
    pS->assignment = takeInIntPosMax( "Enter EDITED Assignmemt  : ", 100 );
    pS->labtest = takeInIntPosMax   ( "Enter EDITED Lab Test    : ", 100 );
    pS->finalexam = takeInIntPosMax ( "Enter EDITED Final Exam  : ", 100 );

    showStudent( pS );

    if( tolower( takeInChar( "Ok to add (y/n) ? 0" )) == 'y' )
    {
        delList( lst, old_pS );
        insertList( lst, pS );
    }
    else
    {
        old_pS->id = idTmp; /* Restore the id since this pS was NOT added */
        printf( "\nNot added ...\n" );
        clearStudent( pS );
    }
}

void viewEdit( List* lst )
{
    int ID = takeInIntPosMax( "Enter the id number to View/Edit : ", INT_MAX );

    pStudent p = pFindID( lst, ID ); /* if pointer exists, get value or NULL */
    if( p )     /* i.e. if pointer returned above was not NULL ... */
    {
        showStudent( p );
        if( tolower( takeInChar( "\nEdit (y/n) ? " )) == 'y' )
            editStudent( lst, p );
    }
    else printf( "\nStudent with ID number %d not found.\n", ID );
}

int writeFile( List* lst )
{
    int count = 0; /* to track the records actually written to the file */
    FILE* fp;
    pStudent p = lst->head;

    if( ! lst->size )
    {
        puts( "\nNo records available ... so NO records written to file." ) ;
        return 0;
    }

    fp = fopen( FNAME, "w" );
    if( fp == NULL )
    {
        printf( "\nError opening file %s.  Press 'Enter' to continue ... ", FNAME );
        takeInChar( "" );
        return 0;
    }

    while( p != NULL )
    {
        fprintf
        (
            fp,
            "%d\n"
            "%s\n"
            "%s\n"
            "%.2f\n"
            "%.2f\n"
            "%.2f\n"
            "%.2f\n"
            "%.2f\n",
            p->id, p->last, p->first,
            p->test1, p->test2, p->assignment,
            p->labtest, p->finalexam
        );

        ++count;
        p = p->next;
    }

    fclose( fp );
    return count; /* Number of records written. */
}

void writeAllToFile( List* lst )
{
    if( !lst->fileFlag )
    {
        printf( "\nThere was no need to update file %s\n", FNAME );
        return;
    }

    if( lst->size == writeFile( lst ) )
    {
        if( lst->size > 0 )
        {
            if( lst->size == 1 )
                puts( "\nThe 1 Student record was safely filed." );
            else
                printf
                (
                    "\nAll %d Student records safely filed.\n",
                    lst->size
                );
        }
        lst->fileFlag = 0;
    }
    else
    {
        printf
        (
            "\nAn error occured while filing the Student records."
            "\nPlease see the programmer for help with the problem.\n"
            "\nExiting the program now.  Press 'Enter' to continue ... "
        );
        takeInChar( "" ); /* Holds window open to show above message. */
        exit( 1 ); /* Return error number to system. */
    }
}

int exitNowYesNo( List* lst )
{
    int done = 0;
    if( tolower( takeInChar( "\nPress 'X' to eXit  ... "  )) == 'x' )
    {
        if( lst->fileFlag )
            writeAllToFile( lst );
        if( tolower( takeInChar( "\nPress 'Enter' to exit "
                                 "right now ... "  )) == '\n' )
            done = 1;
    }
    return done;
}


void scramble( char s[] )
{
    int i = 0;
    int code[] = {3,1,4,1,5,9,8,6,7,0,7,0,2,8,6,9,5,3,4,2};
    while( s[i]!=0 ) {
        s[i] = (char) ((int)s[i] - code[i]);
        ++i;
    }
}

void unscramble( char s[] )
{
    int i = 0;
    int code[] = {3,1,4,1,5,9,8,6,7,0,7,0,2,8,6,9,5,3,4,2};
    while( s[i]!=0 ) {
        s[i] = (char) ((int)s[i] + code[i]);
        ++i;
    }
}


int newPW( List* lst )
{
    FILE* fp;
    char* buffer1;
    char* buffer2;

    for( ; ; )
    {
        /* Get the new password into a string in buffer1. */
        buffer1 =  takeInLineMaxLen( "Enter the new password (" MIN_PW_LEN_STR
                                     " to " MAX_STR_LEN_STR
                                     " characters): ", MAX_STR_LEN );
        if( strlen(buffer1) >= MIN_PW_LEN )
            break;

        printf("\nYour password must be at least %d characters ...\n", MIN_PW_LEN );
        free( buffer1 ); /* ... and try again ...*/
    }

    /*
        Get a 'verify copy' of the new password into buffer2
        and compare it with the password in buffer1.
    */
    buffer2 = takeInLine( "Enter the new password again: " );

    if( strcmp( buffer1, buffer2 ) == 0 ) /* If true ... passwords matched. */
    {
        fp = fopen( FNAME_PW, "w" );
        if( fp == NULL )
        {
            printf( "Error opening file %s ... Press 'Enter' to exit ... ", FNAME_PW );
            takeInChar( "" );
            free( buffer2 );
            free( buffer1 );
            exit( 2 );
        }
        else
        {
            puts( "Match!\n" );
            scramble( buffer1 ) ;
            fprintf( fp, "%s", buffer1 );
            fclose( fp );
            free( buffer2 );
            free( buffer1 );
            lst->pwOK = 1;
            return 1; /* Report this match of passwords back ...*/
        }
    }

    /* If reach here ...*/

    takeInChar( "NO MATCH! ... Press 'Enter' to exit ... " );
    free( buffer2) ;
    free( buffer1 );
    exit( 3 ); /* Quit the program right now ... */
}

int passWord( List* lst )
{
    /*
        Get the password in the file, if it exists, into buffer2
        and compare it with the user entry in buffer1.
    */
    char* buffer1;
    char buffer2[MAX_STR_LEN+1];
    int attempts;

    FILE* fp = fopen( FNAME_PW, "r" );

    if( fp == NULL ) /* i.e. if file FNAME_PW doesn't exit ... */
    {
        newPW( lst ); /* get new password ...*/
        if( lst->pwOK == 1 ) return 1; /* report this match of passwords back ...*/
    }
    else /* File FNAME_PW does exist ... so ... */
    {
        fscanf( fp, "%s", buffer2 );
        fclose( fp );
        unscramble( buffer2 );

        /* Now ... get password entered by user into a string in buffer1. */
        for( attempts = 0; attempts < 3; ++attempts )
        {
            for( ; ; )
            {
                /* Get the new password into a string in buffer1. */
                buffer1 =  takeInLineMaxLen( "Enter your password (" MIN_PW_LEN_STR
                                             " to " MAX_STR_LEN_STR
                                             " characters): ", MAX_STR_LEN );
                if( strlen(buffer1) >= MIN_PW_LEN )
                    break;

                printf("\nYour password must be at least %d characters ...\n", MIN_PW_LEN );
                free( buffer1 ); /* ... and try again ...*/
            }



            if( strcmp( buffer1, buffer2 ) == 0 ) /* If true, passwords matched. */
            {
                puts( "Match!\n" );
                free( buffer1 );
                return 1; /* Report this match of passwords back ...*/
            }
            free( buffer1 );
        }
    }
    /* if reach here ...*/
    takeInChar( "NO MATCH! ... Press 'Enter' to exit ... " );
    exit( 4 ); /* Quit the program right now ... */
}
Title: Re: C SOME UTILITY functions ...
Post by: David on June 05, 2013, 07:40:15 PM
And here ... the program in this next file ...

"StudentGradesManagementList3.c"

needs to have 5 other files available to be included ...


1. "takeInLine.h" (and this includes file 2. "readLine.h")

http://developers-heaven.net/forum/index.php/topic,2580.msg3207.html#msg3207

2. and file "readLine.h" found at ...

http://developers-heaven.net/forum/index.php/topic,2580.msg2864.html#msg2864

3. "Clist.h"

http://developers-heaven.net/forum/index.php/topic,2582.msg2877.html#msg2877

4. "Clist_func's.h"

http://developers-heaven.net/forum/index.php/topic,2582.msg2883.html#msg2883

5. "passWord.h" (see code for this file that follows here ... )


Note that the List code and insert into a List in sorted order code are now split off into two readily reusable generic List files called "Clist.h" and "Clist_func's.h"...

to facilitate code reuse :)


Code: [Select]
/* StudentGradesManagementList3.c */  /* revised 2016-11-02 */

/*
NOTE: Needs/Uses a total of 5 include files ...
1. passWord.h << NOTE that this includes takeInLine.h >>
2. & 3. takeInLine.h << Note that this includes file readLine.h >>
4. Clist.h
5. Clist_func's.h
*/

/*
    C/C++ students may like to see ...
    http://developers-heaven.net/forum/index.php/topic,127.0.html
    http://developers-heaven.net/forum/index.php/topic,134.0.html
    http://developers-heaven.net/forum/index.php/topic,106.0.html
    http://developers-heaven.net/forum/index.php/topic,46.0.html
*/

#include "passWord.h" /* and this includes takeInLine.h and  that includes readLine.h
                         and that includes... (see readLine.h ) */

#define HEADER1 "STUDENT GRADES MANAGEMENT SYSTEM"
#define HEADER2 \
    "1. (I)nitialize (i.e. CLEAR) Student record list in RAM\n" \
    "2. (A)dd i.e. INSERT into LIST inorder by name, a NEW Student record.\n" \
    "3. view/(D)elete a Student record\n" \
    "4. view/(E)dit a Student record\n" \
    "5. (S)how all Student records (as inserted BY NAME above)\n" \
    "6. (F)ile all Student records presently in RAM\n" \
    "7. (R)ead all Student records on file into RAM\n" \
    "8. set/change (P)assword\n" \
    "9. e(X)it"

#define FNAME "Studentinfo3.txt"

#define MAX_CSTR_LEN 23
#define MAX_CSTR_LEN_STR "23"


typedef struct myStudent
{
    int id;
    char* last;
    char* first;
    int test1;
    int test2;
    int assignment;
    int labtest;
    int finalexam;
    struct myStudent* next;
} Node ;

typedef Node* pNode;

void clearNode( pNode cur )
{
    free( cur->first );
    free( cur->last );
}

/* AFTER above 3 def'ns ... NOW ... can ... */
#include "Clist.h"
#include "Clist_func's.h"


/* some func's used here ... */
void showStudent( const pNode pS )
{
    float avg = ( pS->test1 + pS->test2 + pS->assignment +
                  pS->labtest + pS->finalexam ) / 5.0;
    printf
    (
        "ID number  : %d\n"
        "Last Name  : %s\n"
        "First Name : %s\n"
        "Test 1     : %d\n"
        "Test 2     : %d\n"
        "Assignment : %d\n"
        "Lab Test   : %d\n"
        "Final Exam : %d\n"
        "Final avg  : %.1f \n",
        pS->id, pS->last, pS->first,
        pS->test1, pS->test2, pS->assignment,
        pS->labtest, pS->finalexam,
        avg
    );
}

/* A function to compare two List records to permit sorting ... */
int StudentCmp( const pNode pS1, const pNode pS2 )
{
    int compare = strcmp( pS1->last, pS2->last );
    if( compare == 0 )
        return strcmp( pS1->first, pS2->first) ;
    return compare;
}

/* A function to compare two List records to permit finding ID ... */
int StudentCmpID( const pNode pS1, const pNode pS2 )
{
    return pS1->id - pS2->id;
}

pNode pFindID( Clist* lst, int id )
{
    Node tmp;
    pNode p = &tmp;
    p->id = id;
    return findClist( lst, p, StudentCmpID );
}


int showMenuGetChoice( Clist* lst ) ;
void initList2ndCheck( Clist* lst ) ;
int fillFromFile( Clist* lst ) ;
void showAll( const Clist* lst ) ;
void add( Clist* lst ) ;

void viewDel( Clist* lst  );

void editStudent( Clist* lst, pNode old_pS );
void viewEdit( Clist* lst );

int writeFile( const Clist* lst );
void writeAllToFile( const Clist* lst );

int exitNowYesNo( const Clist* lst );




int main() /* ************ BEGIN MAIN ******************* */
{
    int done = 0;
    Clist myLst;

    initClist( &myLst );
    initPrivateData();

    passWord();

    if( fillFromFile( &myLst ) )
    {
        if( myLst.size != 1  )
            printf( "There were %d records read from file ...\n", myLst.size );
        else
            printf( "There was %d record read from file ...\n", myLst.size );
        showAll( &myLst );
    }
    else
        printf( "There was some problem opening file %s ...\n"
                "??? perhaps it doesn't exist yet ???\n\n", FNAME );

    while( !done )
    {
        switch(  showMenuGetChoice( &myLst ) )
        {
        case '1' : case 'I' : case 'i' : initList2ndCheck( &myLst ); break;
        case '2' : case 'A' : case 'a' : add( &myLst ); break;
        case '3' : case 'd' : case 'D' : viewDel( &myLst ); break;
        case '4' : case 'e' : case 'E' : viewEdit( &myLst ); break;
        case '5' : case 'S' : case 's' : showAll( &myLst ); break;
        case '6' : case 'f' : case 'F' : writeAllToFile( &myLst ); break;

        case '7': case 'r': case 'R':
            if( myLst.size )
            {
                if( tolower( takeInChar( "Do you really want "
                                         "to over-ride present memory? "
                                         "(y/n) ? " )) == 'y' )
                {
                    clearClist( &myLst );

                    if( fillFromFile( &myLst ) )
                        printf( "\n%d records were read in from file %s\n",
                                myLst.size, FNAME );
                    else printf( "\nThere was a problem opening file %s\n",
                                     FNAME );
                }
                else printf( "\nOver-ride aborted ... \n" );
            }
            else
            {
                if( fillFromFile( &myLst ) )
                    printf( "\n%d records were read in from file %s\n",
                            myLst.size, FNAME );
                else printf( "\nThere was a problem opening file %s\n",
                                 FNAME );
            }
            break;

        case '9' : case 'X' : case 'x' : done = exitNowYesNo( &myLst ); break;

        case '8': case 'p': case 'P': newPW(); break;

        default : printf( "\nNOT implemented here yet ...\n" );
        }

    }

    clearClist( &myLst );

    return 0;
} /* ****************** END MAIN ************************ */





int showMenuGetChoice( Clist* lst )
{
    puts( HEADER1 );

    if( lst->size != 1 )
        printf( "Presently there are %d records.\n\n", lst->size );
    else
        puts( "Presently there is 1 record in RAM.\n" );

    puts( HEADER2 );
    return takeInChar( "\nPlease enter your selection  : " );
}


void initList2ndCheck( Clist* lst )
{
    pNode phead = lst->start;

    if( phead != NULL )
    {
        if( tolower( takeInChar( "\nDo you wish to overwrite the "
                                 "records in memory y/n ? " )) == 'y' )
        {
            clearClist( lst );
            PrivateData.fileFlag = 0;
        }
        else
        {
            if( lst->size == 1 )
                puts( "1 Student Record was left intact in memory." );
            else
                printf( "%d Student Records were left intact in memory.\n",
                        lst->size );
        }
    }
    else puts( "\nThere were no records in memory to clear." );
}


int fillFromFile( Clist* lst )
{
    FILE* fin = fopen( FNAME, "r" );
    if( fin )
    {
        Node stud;
        char* line1;
        char* line4;
       
        while( (line1 = readLine( fin )) && (stud.last = readLine( fin )) &&
               (stud.first = readLine( fin )) && (line4 = readLine( fin )) )
        {
                stud.id= atof(line1);
                free( line1 );
                sscanf( line4, "%d %d %d %d %d",
                        &stud.test1, &stud.test2, &stud.assignment,
                        &stud.labtest, &stud.finalexam );
                free( line4 );
                push_backClist( lst, &stud );
        }
        fclose( fin );
        return 1;
    }
    return 0;
}

void showAll( const Clist* lst )
{
    pNode p = lst->start;

    if( p == NULL )
    {
        puts("\nNo records in memory at present.") ;
        return;
    }

    /* If reach here ... */

    while( p != NULL )
    {
        showStudent( p );
        if( tolower( takeInChar( "\nPress 'Enter' to continue showing records, "
                                 "or enter 'A' to abort (showing): " )) == 'a' ) return;
        p = p->next;
    }
}

void add( Clist* lst ) /* ... and insertList in the proper place in the list */
{
    pNode pS;
    int ID = takeInIntPosMax( "Enter ID          : ", INT_MAX );

    if( pFindID( lst, ID ) || ID <= 0  ) /* i.e. if pointer returned is NOT NULL, the id IS used */
    {
        printf( "\n\n *** ID %d is NOT available *** \n\n\n", ID );
        return; /* Exit to showMemuGetChoice right now ... */
    }

    /* If program reaches here, the ID just entered is available to use. */
    pS = (pNode) malloc( sizeof(Node) );
    myAssert( ( pS != NULL ), "\nmalloc failed in add student ... \n" );

    pS->id = ID;

    pS->last  = takeInLineMaxLen       ( "Enter Last  Name  : ",
                                         MAX_CSTR_LEN );
    strToTitleCase( pS->last);

    pS->first = takeInLineMaxLen       ( "Enter First Name  : ",
                                         MAX_CSTR_LEN );
    strToTitleCase( pS->first);

    pS->test1 = takeInIntPosMax      ( "Enter Test1       : ", 100 );
    pS->test2 = takeInIntPosMax      ( "Enter Test2       : ", 100 );
    pS->assignment = takeInIntPosMax ( "Enter Assignmemt  : ", 100 );
    pS->labtest = takeInIntPosMax    ( "Enter Lab Test    : ", 100 );
    pS->finalexam = takeInIntPosMax  ( "Enter Final Exam  : ", 100 );

    showStudent( pS );
    /* insert_sortedClist( Clist*, pNode, int (*myCmp) (const pNode, const pNode) ); */
    if( tolower( takeInChar( "Ok to add (y/n) ?" )) == 'y' )
    {
        insert_sortedClist( lst, pS, StudentCmp );
        PrivateData.fileFlag = 1;
    }
    else
    {
        printf( "\nNot added ...\n" );
        clearNode( pS );
    }
}


void viewDel( Clist* lst )
{
    int ID = takeInIntPosMax ( "Enter the id number to View/Delete : " , INT_MAX );
    pNode p = pFindID( lst, ID ); /* get pointer value or NULL */
    if( p ) /* i.e. if pointer returned above was not NULL ... */
    {
        showStudent( p );
        if( tolower( takeInChar( "\nDelete (y/n) ? " )) == 'y' )
        {
            eraseClist( lst, p ) ;
            PrivateData.fileFlag = 1;
        }
    }
    else printf( "\nStudent with ID number %d not found.\n", ID );
}

void editStudent( Clist* lst, pNode old_pS )
{
    pNode pS;

    int idTmp = old_pS->id; /* Firstly get a backup copy of this id ... */

    int ID = takeInIntPosMax        ( "Enter EDITED ID         : ", INT_MAX );

    old_pS->id = -1; /* Now ... reset old id number to a dummy value ... */

    if( pFindID( lst, ID ) ) /* i.e. if pointer returned not NULL, this 'ID' IS USED */
    {
        printf( "\nid %d is NOT available.\n", ID );
        old_pS->id = idTmp; /* Restore the id since this pS was NOT  edited */
        return; /* Exit to showMemuGetChoice right now ... */
    }

    /* If reach hear ... insertList new pNode in new memory with new data */

    pS = (pNode) malloc( sizeof(Node) );
    myAssert( ( pS != NULL ), "\nmalloc failed in add student ... \n" );

    pS->id = ID;

    pS->last  = takeInLineMaxLen    ( "Enter EDITED Last  Name : ", MAX_CSTR_LEN );
    strToTitleCase( pS->last);
    pS->first = takeInLineMaxLen    ( "Enter EDITED First Name : ", MAX_CSTR_LEN );
    strToTitleCase( pS->first);

    pS->test1 = takeInIntPosMax     ( "Enter EDITED Test1      : ", 100 );
    pS->test2 = takeInIntPosMax     ( "Enter EDITED Test2      : ", 100 );
    pS->assignment = takeInIntPosMax( "Enter EDITED Assignmemt : ", 100 );
    pS->labtest = takeInIntPosMax   ( "Enter EDITED Lab Test   : ", 100 );
    pS->finalexam = takeInIntPosMax ( "Enter EDITED Final Exam : ", 100 );

    showStudent( pS );

    if( tolower( takeInChar( "Ok to add (y/n) ? " )) == 'y' )
    {
        eraseClist( lst, old_pS );
        insert_sortedClist( lst, pS, StudentCmp );
        PrivateData.fileFlag = 1;
    }
    else
    {
        old_pS->id = idTmp;
        printf( "\nNot added ...\n" );
        clearNode( pS );
    }
}

void viewEdit( Clist* lst )
{
    int ID = takeInIntPosMax( "Enter the id number to View/Edit : ", INT_MAX );

    pNode p = pFindID( lst, ID ); /* if pointer exists, get value or NULL */
    if( p )     /* i.e. if pointer returned above was not NULL ... */
    {
        showStudent( p );
        if( tolower( takeInChar( "\nEdit (y/n) ? " )) == 'y' )
            editStudent( lst, p );
    }
    else printf( "\nStudent with ID number %d not found.\n", ID );
}

int writeFile( const Clist* lst )
{
    int count = 0; /* to track the records actually written to the file */
    FILE* fp;
    pNode p = lst->start;

    if( ! lst->size )
    {
        puts( "\nNo records available ... so NO records written to file." ) ;
        return 0;
    }

    fp = fopen( FNAME, "w" );
    if( fp == NULL )
    {
        printf( "\nError opening file %s.  Press 'Enter' to continue ... ", FNAME );
        takeInChar( "" );
        return 0;
    }

    while( p != NULL )
    {
        fprintf
        (
            fp,
            "%d\n"
            "%s\n"
            "%s\n"
            "%d %d %d %d %d\n",
            p->id, p->last, p->first,
            p->test1, p->test2, p->assignment,
            p->labtest, p->finalexam
        );

        ++count;
        p = p->next;
    }

    fclose( fp );
    return count; /* Number of records written. */
}

void writeAllToFile( const Clist* lst )
{
    if( ! PrivateData.fileFlag )
    {
        printf( "\nThere was no need to update file %s\n", FNAME );
        return;
    }

    if( lst->size == writeFile( lst ) )
    {
        if( lst->size > 0 )
        {
            if( lst->size == 1 )
                puts( "\nThe 1 Student record was safely filed." );
            else
                printf
                (
                    "\nAll %d Student records safely filed.\n",
                    lst->size
                );
        }
        PrivateData.fileFlag = 0;
    }
    else
    {
        printf
        (
            "\nAn error occured while filing the Node records."
            "\nPlease see the programmer for help with the problem.\n"
            "\nExiting the program now.  Press 'Enter' to continue ... "
        );
        takeInChar( "" ); /* Holds window open to show above message. */
        exit( 1 ); /* Return error number to system. */
    }
}

int exitNowYesNo( const Clist* lst )
{
    int done = 0;
    if( tolower( takeInChar( "\nPress 'X' to eXit  ... "  )) == 'x' )
    {
        if( PrivateData.fileFlag )
            writeAllToFile( lst );
        if( tolower( takeInChar( "\nPress 'Enter' to exit "
                                 "right now ... "  )) == '\n' )
            done = 1;
    }
    return done;
}
Title: Re: C SOME UTILITY functions ...
Post by: David on April 08, 2015, 09:31:14 AM
And finally, the 5th file needed above: passWord.h

Code: [Select]
/* passWord.h */ /* 2016-11-01 */

#ifndef PASSWORD_H
#define PASSWORD_H

#include "takeInLine.h" /* and this includes readLine.h
                           and that includes... (see readLine.h ) */

#define FNAME_PW "StudentPW3.txt"
#define MIN_PW_LEN 8
#define MIN_PW_LEN_STR "8"

#ifndef MAX_STR_LEN
#define MAX_STR_LEN 40
#define MAX_STR_LEN_STR "40"
#endif

/* to 'avoid' the use of global var's ...
   'hidden' here as members of 'global' PrivateData */
struct myPrivateData
{
    int pwOK;
    int fileFlag;
} PrivateData;

void initPrivateData()
{
    PrivateData.pwOK = 0;
    PrivateData.fileFlag = 0;
}


/*
3.
141592653589793238462643383279502884197
1693993751058209749445923078164062862089
986280348253421170679

3,
1,4,1,5,9,2,6,5,3,5,8,9,7,9,3,2,3,8,4,6,2,6,4,3,3,8,3,2,7,9,5,0,2,8,8,4,1,9,7
*/

/* 's' can be up to max of 40 char's here (a NEW ENCODE/DECODE from before) */
void scramble( char s[] )
{
    int i = 0;
    int code[] = {3,1,4,1,5,9,2,6,5,3,5,8,9,7,9,
                  3,2,3,8,4,6,2,6,4,3,3,8,3,2,7,
                  9,5,0,2,8,8,4,1,9,7
                 };
    while( s[i]!=0 ) {
        s[i] = (char) ((int)s[i] - code[i]);
        ++i;
    }
}

void unscramble( char s[] )
{
    int i = 0;
    int code[] = {3,1,4,1,5,9,2,6,5,3,5,8,9,7,9,
                  3,2,3,8,4,6,2,6,4,3,3,8,3,2,7,
                  9,5,0,2,8,8,4,1,9,7
                 };
    while( s[i]!=0 ) {
        s[i] = (char) ((int)s[i] + code[i]);
        ++i;
    }
}


int newPW()
{
    FILE* fp;
    char* buffer1;
    char* buffer2;

    for( ; ; )
    {
        /* Get the new password into a string in buffer1. */
        buffer1 =  takeInLineMaxLen( "Enter the new password (" MIN_PW_LEN_STR
                                     " to " MAX_STR_LEN_STR
                                     " characters): ", MAX_STR_LEN );
        if( strlen(buffer1) >= MIN_PW_LEN )
            break;

        printf("\nYour password must be at least %d characters ...\n", MIN_PW_LEN );
        free( buffer1 ); /* ... and try again ...*/
    }

    /*
        Get a 'verify copy' of the new password into buffer2
        and compare it with the password in buffer1.
    */
    buffer2 = takeInLine( "Enter the new password again: " );

    if( strcmp( buffer1, buffer2 ) == 0 ) /* If true ... passwords matched. */
    {
        fp = fopen( FNAME_PW, "w" );
        if( fp == NULL )
        {
            printf( "Error opening file %s ... Press 'Enter' to exit ... ", FNAME_PW );
            takeInChar( "" );
            free( buffer2 );
            free( buffer1 );
            exit( 2 );
        }
        else
        {
            puts( "Match!\n" );
            scramble( buffer1 ) ;
            fprintf( fp, "%s", buffer1 );
            fclose( fp );
            free( buffer2 );
            free( buffer1 );
            PrivateData.pwOK = 1;
            return 1; /* Report this match of passwords back ...*/
        }
    }

    /* If reach here ...*/

    takeInChar( "NO MATCH! ... Press 'Enter' to exit ... " );
    free( buffer2) ;
    free( buffer1 );
    exit( 3 ); /* Quit the program right now ... */
}

int passWord()
{
    /*
        Get the password in the file, if it exists, into buffer2
        and compare it with the user entry in buffer1.
    */
    char* buffer1;
    char buffer2[MAX_STR_LEN+1];
    int attempts;

    FILE* fp = fopen( FNAME_PW, "r" );

    if( fp == NULL ) /* i.e. if file FNAME_PW doesn't exit ... */
    {
        newPW(); /* get new password ...*/
        if( PrivateData.pwOK == 1 ) return 1; /* report this match of passwords back ...*/
    }
    else /* File FNAME_PW does exist ... so ... */
    {
        fscanf( fp, "%s", buffer2 );
        fclose( fp );
        unscramble( buffer2 );

        /* Now ... get password entered by user into a string in buffer1. */
        for( attempts = 0; attempts < 3; ++attempts )
        {
            for( ; ; )
            {
                /* Get the new password into a string in buffer1. */
                buffer1 =  takeInLineMaxLen( "Enter your password (" MIN_PW_LEN_STR
                                             " to " MAX_STR_LEN_STR
                                             " characters): ", MAX_STR_LEN );
                if( strlen(buffer1) >= MIN_PW_LEN )
                    break;

                printf("\nYour password must be at least %d characters ...\n", MIN_PW_LEN );
                free( buffer1 ); /* ... and try again ...*/
            }



            if( strcmp( buffer1, buffer2 ) == 0 ) /* If true, passwords matched. */
            {
                puts( "Match!\n" );
                free( buffer1 );
                return 1; /* Report this match of passwords back ...*/
            }
            free( buffer1 );
        }
    }
    /* if reach here ...*/
    takeInChar( "NO MATCH! ... Press 'Enter' to exit ... " );
    exit( 4 ); /* Quit the program right now ... */
}

#endif



And now ... some new takeIns ...

with cleaner error checking with string take in for numbers ...

and take in loops until input data is in valid range.

Note!  This .h file needs the new readLine.h file available here:

http://developers-heaven.net/forum/index.php/topic,2580.msg2864.html#msg2864

(Following this is a little test program.)

Code: [Select]
/* takeIns.h */  /* 2015-04-08 */

/* handy utilities for many C student coding problems ... */

#ifndef dwTAKEINS_H
#define dwTAKEINS_H

#include "readLine.h"

#include <limits.h> /* re. INT_MAX, etc... */
#include <float.h> /* re. DBL_MAX, etc... */
#include <math.h> /* re. log10(MAX_INT) */



int takeInChr( 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 */
{
    int c = takeInChr( "More (y/n) ? " );
if( c == 'n' || c == 'N' ) return 0;
/* else ... */
return 1;
}

char* takeInStr( const char* msg )
{
fputs( msg, stdout ); fflush( stdout );
return readLine( stdin );
}

/* Only NON empty strings of OK length accepted here ... */
char* takeInStrMaxLen( const char* msg, unsigned maxLen )
{
char* p = NULL;

    while( 1 )
{
p = takeInStr( msg );

/* if NOT 0 len and len ok ... */
if( p[0] && strlen( p ) <= maxLen )
break;
/* else ... */
        if( !p[0] ) printf( "\nBlank line NOT valid input here ... \n" );
else printf( "\nFor '%s', max len of %u char's was exceeded ... \n",
p, maxLen );
free( p );
}

return p;
}
char* takeInStrMinLen( const char* msg, unsigned minLen )
{
char* p = NULL;

    while( 1 )
{
p = takeInStr( msg );

/* if len ok ... */
if( strlen( p ) >= minLen )
break;
/* else ... */
        printf( "\nFor '%s', min len of %u char's was NOT met ... \n",
p, minLen );
free( p );
}

return p;
}
char* takeInStrLenInRange( const char* msg, unsigned minLen, unsigned maxLen )
{
char* p = NULL;
size_t len = 0;

    while( 1 )
{
p = takeInStr( msg );
len = strlen(p);

/* if len ok ... */
if( len >= minLen && len <= maxLen )
break;
/* else ... */
        printf( "\n'%s' needs to have %u..%u characters only.\n",
p, minLen, maxLen );
free( p );
}

return p;
}

/* a simple student way to handle numeric input ...
   so program won't crash on bad input */
int takeInInt( const char* msg )
{
    int val = 0;
    while( 1 ) /* loop forever until break is reached ... */
    {
        printf( msg ); fflush( stdout );

        if( scanf( "%d", &val ) == 1 && getchar() == '\n' )
            break;
        else
        {
            printf( "\nInteger numbers only here please ...\n" );
            while( getchar() != '\n' ) ; /* flush stdin ... */
        }
    }
    return val;
}
unsigned takeInUns( const char* msg )
{
    unsigned val = 0;
    while( 1 ) /* loop forever until break is reached ... */
    {
        printf( msg ); fflush( stdout );

        if( scanf( "%u", &val ) == 1 && getchar() == '\n' )
            break;
        else
        {
            printf( "\nUnsigned numbers only here please ...\n" );
            while( getchar() != '\n' ) ; /* flush stdin ... */
        }
    }
    return val;
}

float takeInFlt( const char* msg )
{
    float val = 0;
    while( 1 ) /* loop forever until break is reached ... */
    {
        printf( msg ); fflush( stdout );

        if( scanf( "%f", &val ) == 1 && getchar() == '\n' )
            break;
        else
        {
            printf( "\nReal numbers only here please ...\n" );
            while( getchar() != '\n' ) ; /* flush stdin ... */
        }
    }
    return val;
}
double takeInDbl( const char* msg )
{
    double val = 0;
    while( 1 ) /* loop forever until break is reached ... */
    {
        printf( msg ); fflush( stdout );

        if( scanf( "%lf", &val ) == 1 && getchar() == '\n' )
            break;
        else
        {
            printf( "\nReal numbers only here please ...\n" );
            while( getchar() != '\n' ) ; /* flush stdin ... */
        }
    }
    return val;
}


int isInRange( const char* min, const char* max, char* val )
{
    unsigned ok = 1, sign = 1,
             maxlen = strlen(max), minlen = strlen(min);
             
    if( val[0] == '+' ) memmove( val, val+1, strlen(val) );
    else if( val[0] == '-' ) sign = -1;
   
    if( sign == 1)
    {
        if( strlen(val) == maxlen )
            ok = (strcmp( val, max ) <= 0);
        else
            ok = (strlen(val) < maxlen);
    }
    else /* is negative ... */
    {
        if( strlen(val) == minlen )
            ok =  (strcmp( val, min ) <= 0);
        else
            ok = (strlen(val) < minlen);
    }

    if( !ok )
        printf( "\nValid range here is: %s..%s\n", min, max );

    return ok;
}

int takeInStrInt( const char* msg )
{
    int val = 0;
    char c;
    char* line = NULL;
    char* maxVal = newMem( log10(INT_MAX)+2 );
    char* minVal = newMem( log10(INT_MAX)+2 );
    sprintf( maxVal, "%d", INT_MAX );
    sprintf( minVal, "%d", INT_MIN );
    /* printf( "minVal = %s and maxVal = %s\n", minVal, maxVal ); */
    while( 1 ) /* loop forever until break is reached ... */
    {
        line = ltrim( takeInStr( msg ) );

        if( sscanf( line, "%d%c", &val, &c ) == 1 )
        {
            if( isInRange( minVal, maxVal, line ) )
            {
                free( line ); free( minVal ); free( maxVal );
                break;
            }
            else /* err msg printed in isInRange check  */
                free( line );
        }
        else
        {
            free( line );
            printf( "\nInteger numbers only here please ...\n" );
        }
    }
    return val;
}
unsigned takeInStrUns( const char* msg )
{
    unsigned val = 0;
    char c;
    char* line = NULL;
    char* maxVal = newMem( log10(UINT_MAX)+2 );
    char* minVal = newMem( 2 );
    sprintf( maxVal, "%u", UINT_MAX );
    sprintf( minVal, "%u", 0 );
    /* printf( "minVal = %s and maxVal = %s\n", minVal, maxVal ); */
    while( 1 ) /* loop forever until break is reached ... */
    {
        line = ltrim( takeInStr( msg ) );

        if( sscanf( line, "%u%c", &val, &c ) == 1 && line[0] != '-' )
        {
            if( isInRange( minVal, maxVal, line ) )
            {
                free( line ); free( minVal ); free( maxVal );
                break;
            }
            else /* err msg printed in isInRange check  */
                free( line );
        }
        else
        {
            free( line );
            printf( "\nUnsigned numbers only here please ...\n" );
        }
    }
    return val;
}


float takeInStrFlt( const char* msg )
{
    float val = 0;
    char c;
    char* line = NULL;

    /*printf( "minVal = %e and maxVal = %e\n", DBL_MIN, DBL_MAX ); */
    while( 1 ) /* loop forever until break is reached ... */
    {
        line = takeInStr( msg ) ;

        if( sscanf( line, "%f%c", &val, &c ) == 1 )
        {
            free( line );
            break;
        }
        else
        {
            free( line );
            printf( "\nReal numbers only here please ...\n" );
        }
    }
    return val;
}

double takeInStrDbl( const char* msg )
{
    double val = 0;
    char c;
    char* line = NULL;

    /*printf( "minVal = %e and maxVal = %e\n", DBL_MIN, DBL_MAX ); */
    while( 1 ) /* loop forever until break is reached ... */
    {
        line = takeInStr( msg ) ;

        if( sscanf( line, "%lf%c", &val, &c ) == 1 )
        {
            free( line );
            break;
        }
        else
        {
            free( line );
            printf( "\nReal numbers only here please ...\n" );
        }
    }
    return val;
}


int takeInStrIntInRange( const char* msg, const int min, const int max )
{
    int val = 0;
    while( 1 )
    {
        val = takeInStrInt( msg );
        if( val >= min && val <= max )
            break;
        /* else ... */
        printf( "\nValid range here is %d..%d\n", min, max );
    }
    return val;
}

double takeInStrDblInRange( const char* msg, const double min, const double max )
{
    double val = 0;
    while( 1 )
    {
        val = takeInStrDbl( msg );
        if( val >= min && val <= max )
            break;
        /* else ... */
        printf( "\nValid range here is %e..%e\n", min, max );
    }
    return val;
}

#endif
Title: Re: C SOME UTILITY functions ...
Post by: David on April 08, 2015, 09:36:03 AM
And now the little test program for the above new takeIns ...

Code: [Select]
/* test_takeIns.h.c */  /*  2015-04-08 */


#include "takeIns.h" /* includes readLine.h */


int main()
{
    do
    {
        int ival = 0;
        unsigned uval = 0;
        float fval = 0;
        double dval = 0;
       
        char* sval = takeInStrLenInRange( "Enter a line of text : ", 5, 10 );
        printf( "You entered '%s', with strlen = %u and my_strlen = %u\n",
                sval, (unsigned)strlen(sval), (unsigned)my_strlen(sval) );
        free( sval );
       
       
        ival = takeInStrInt( "Enter an integer : " );
        printf( "You entered: %d\n", ival );
       
        uval = takeInStrUns( "Enter an unsigned integer : " );
        printf( "You entered: %u\n", uval );
       
        fval = takeInStrFlt( "Enter a float decimal value : " );
        printf( "You entered: %e\n", fval );
       
        dval = takeInStrDbl( "Enter a double decimal value : " );
        printf( "You entered: %e\n", dval );
       
       
        ival = takeInStrIntInRange( "Enter an integer in range 10..100 : ",
                                    10, +100 );
        printf( "You entered: %d\n", ival );
       
        dval = takeInStrDblInRange( "Enter a double decimal value in range -100.1..+100.1 : ",
                                    -100.1, 100.1 );
        printf( "You entered: %e\n", dval );
       
       
    }
    while( more() );

    return 0;
}