//========================================================================= //#define PROGRAMMER "BAHN, William" //#define PROG_CODE "bahw" //#define COURSE "ECE-1021" //#define YEAR (2003) //#define TERM "Fall" //#define SECTION (0) //#define ASSIGNMENT "Utility Functions" //#define REVISION (2) //#define TITLE "Dirty Deeds Done Dirt Cheap" //#define SUBTITLE "Last Modified: 02 DEC 03" //#define EMAIL "wbahn@eas.uccs.edu" //#define FILENAME "DirtyD.h" //========================================================================= // GENERAL DESCRIPTION // // This file contains many useful functions - and more are added from time // to time. // REVISION HISTORY // REV 2: 02 DEC 03 // // Added the GetBoundedInt() function // Added the GetBoundedDouble() function // Added the InBounds() macro // Added the GetInt() function // Added the GetDouble() function // REV 1: 28 NOV 03 // // Added the PI macro (good to 20 digits) // Added the StripCR() function. // Added the ClearBuffer() function. // Added the WaitForKey() function. // REV 0: 09 NOV 03 // // Initial Creation. #ifndef DirtyDdotH // This directive prevents the prototypes and, most importantly, the // function definitions (which would normally be in a separate .c file) // from being included more than once. // // At the end of the excluded block of code, the identifier is defined. //========================================================================= //== INCLUDE FILES ======================================================== //========================================================================= #include // printf(), NULL #include // exit() #include // strlen() #include // kbhit(), getch() //========================================================================= //== MACRO DEFINITIONS ==================================================== //========================================================================= #define FALSE (0) #define TRUE (!FALSE) #define PI (3.1415926358979323846) #define RET_DEFAULT (0) #define RET_CLIPPED (1) #define InBounds(min, test, max) ( ((min) <= (test)) && ((test) < (max)) ) //========================================================================= //== MISCELLANEOUS FUNCTION PROTOTYPES ==================================== //========================================================================= void PrintHeader(void); char *StripCR(char *s); char *GetFileName(char *name, char *ext, int size); FILE *OpenAndVerify(char *name, char *mode); int rand_int(int min, int max); double rand_norm(void); double rand_fp(double xmin, double max); void ExitIfError(int errcode); int GetBoundedInt(int min, int max, int def, int mode); double GetBoundedDouble(double min, double max, double def, int mode); int GetInt(int min, int max); double GetDouble(double min, double max); // The following functins are not ANSI compliant (they use conio.h) char CatchKey(void); void ClearBuffer(void); void WaitForKey(void); //========================================================================= //== MISCELLANEOUS FUNCTION DEFINITIONS =================================== //========================================================================= //========================================================================= // FUNCTION: PrintHeader() // #include // printf() //========================================================================= #ifdef PROGRAMMER // This function assumes that the #define statements that create these // identifiers are used, typically in the function where main() is defined. // // By checking if one of them is declared, this function can be skipped if // necessary so that the other functions can be used. However, if this // function IS to be available, then it is important that the compiler // encounter the necessary #define statements before this file is included // for the very first time. void PrintHeader(void) { printf("========================================" "=======================================\n"); printf("Course....... %s-%i (%s %i)\n", COURSE, SECTION, TERM, YEAR); printf("Programmer... %s (%s)\n", PROGRAMMER, PROG_CODE); printf("Assignment... %s (Rev %i) (Source Code in %s)\n", ASSIGNMENT, REVISION, FILENAME); printf("Description.. %s\n", TITLE); printf(" %s\n", SUBTITLE); printf("========================================" "=======================================\n"); return; } #endif //========================================================================= // FUNCTION: StripCR() //========================================================================= // This functions strips any trailing Carriage Returns from the end of a // string. In order to catch carriage returns that might be embedded in // the middle of a string, it scans the string from the beginning and looks // for a Line Feed, or a Carriage Return and replaces the first occurance // with a NULL terminator. The use of a do/while() loop allows the test // to operate on the character just examined (and possibly modified) so // that is exits correctly regardless of the NULL terminitor found was // inserted by the loop or was part of the original string. char *StripCR(char *s) { int i; i = -1; do { switch(s[++i]) { case 10: // Line Feed case 13: // Carriage Return s[i] = '\0'; } } while('\0' != s[i]); return(s); } //========================================================================= // FUNCTION: GetFileName() //========================================================================= // This functions gets the a file name from the standard input device and // returns a string pointer to it. There are several modes in which it can // be used. // // The simplest is to pass null arguments for the name and ext variables // and 0 for the size. This tells the function to dynamically allocate // enough memory to accommodate whatever is submitted and to return a // pointer to the allocated memory. // // Example: // // char *filename; // // filename = GetFileName(NULL, NULL, 0); // // The next easiest way is to allocate memory yourself for the string and // tell the function where that memory is located. This is most often done // using a statically allocate character array but previously allocated // dynamic memory will work the same way. Here you MUST tell the function // how much memory is available for the string. The function will ensure // that the string does not exceed the indicated size, including the null // terminator. // // Example: // // char filename[13]; // // GetFileName(filename, NULL, 13); // // If you provide a non-NULL pointer for name and you indicate a size of // zero, the function will assume that the pointer is for previously // allocated memory that is to be freed and then the pointer re-used to // point to new memory. Therefore, do NOT pass the name of a static array // under these conditions as a runtime error will result. // // The ext argument can be used to provide a default file extension. If // the user enters an extension, this parameter will be ignored. If the // user does not include an extension, the one supplied will be appended. // Whether the user entered an extension is determined by checking for the // presence of a period anywhere in the string. // // If the given value for ext is NULL, then no extension will be added // even if the user does not supply one. If the value given for ext is // a pointer to a null string (i.e., ""), then if an extension is not // supplied by the user an empty extension will be added - meaning that // the '.' delimiter will be added but nothing more. char *GetFileName(char *name, char *ext, int size) { int length; char c; int endloop; int extgiven; // Check if size is negative if(0>size) return(NULL); // Check to see if string is static or dynamic if((NULL == name) || (0 == size)) { // String is dynamic length = 0; name = realloc(name, length + 1); name[length] = '\0'; } else { // String is static or fixed length if(size < (strlen(ext)+3) ) // Extension too long, ignore it. ext = NULL; } endloop = FALSE; extgiven = FALSE; while(!endloop) { // Check if there is enough room for another character in string. if( (0 < size) && !(length < size) ) endloop = TRUE; switch(c = getchar()) { case EOF: // End of File found case 10: // Form Feed encountered case 13: // Carriage Return encountered endloop = TRUE; break; case '.': // Extension Delimiter found extgiven = TRUE; default : // All characters (including delimiter above) name = realloc(name, length + 2); name[length++] = c; name[length] = '\0'; break; } } // Check if user supplied an extension and use default if appropriate. if( (!extgiven)&&(NULL != ext) ) { if(0 == size) // dynamic array { // Allocated additional memory for the extension name = realloc(name, length + strlen(ext) + 2); } else // static or fixed length array { // Ensure that the static array can take the extension name[size - strlen(ext) - 2] = '\0'; } strcat(name, "."); strcat(name, ext); } return(name); } //========================================================================= // FUNCTION: OpenAndVerify() // #include // fopen(), FILE, printf() // #include // exit() //========================================================================= FILE *OpenAndVerify(char *name, char *mode) { FILE *fp; fp = fopen(name, mode); if(NULL == fp) { printf("ABORT! - Failed to open file <%s> (mode %s)\n", name, mode); exit(1); } return fp; } //========================================================================= // FUNCTION: rand_int() // #include // rand() //========================================================================= // This function returns a random integer value between min and max // inclusive. int rand_int(int min, int max) { return( rand()%( (max-min) + 1) + min ); } //========================================================================= // FUNCTION: rand_norm() // #include // rand(), RAND_MAX //========================================================================= // This function returns a random floating point value between 0.0 and 1.0 // inclusive. double rand_norm(void) { return( (double)rand()/(double)RAND_MAX ); } //========================================================================= // FUNCTION: rand_fp() //========================================================================= // This function returns a random floating point value between min and max // inclusive. double rand_fp(double min, double max) { return(min + rand_norm()*(max-min)); } //========================================================================= // FUNCTION: ExitIfError() //========================================================================= void ExitIfError(int errcode) { if(errcode) { printf("Abort! (Error #%i detected)\n", errcode); exit(errcode); } return; } //========================================================================= // GetBoundedInt() // This function gets an int from the keyboard and checks if it is within // the specified limits. If it is, then that value is returned, otherwise // the limit that is violated is returned if the mode is set RET_CLIPPED. // Otherwise, the def(ault) value is returned (use RET_DEFAULT). //========================================================================= int GetBoundedInt(int min, int max, int def, int mode) { int i; scanf("%i", &i); if(i < min) i = (RET_CLIPPED == mode)? min : def; if(i > max) i = (RET_CLIPPED == mode)? max : def; return(i); } //========================================================================= // GetBoundedDouble() // This function gets a double from the keyboard and checks if it is within // the specified limits. If it is, then that value is returned, otherwise // the limit that is violated is returned if the mode is set RET_CLIPPED // Otherwise, the def(ault) value is returned (use RET_DEFAULT). //========================================================================= double GetBoundedDouble(double min, double max, double def, int mode) { double x; scanf("%lf", &x); if(x < min) x = (RET_CLIPPED == mode)? min : def; if(x > max) x = (RET_CLIPPED == mode)? max : def; return(x); } //========================================================================= // GetInt() // This function calls GetBoundedInt with an embedded CLIPPED option. //========================================================================= int GetInt(int min, int max) { return(GetBoundedInt(min, max, 0, RET_CLIPPED)); } //========================================================================= // GetDouble() // This function calls GetBoundedDouble with an embedded CLIPPED option. //========================================================================= double GetDouble(double min, double max) { return(GetBoundedDouble(min, max, 0, RET_CLIPPED)); } //========================================================================= // FUNCTION: CatchKey() NOT ANSI COMPLIANT! // #include // kbhit(), getch() //========================================================================= // This function clears out the keyboard buffer and then waits for a // keystroke which it then returns. It does not clear the buffer of any // additional keystrokes before returning. char CatchKey(void) { ClearBuffer(); WaitForKey(); while(!kbhit()); // Stall until key hit return(getch()); } //========================================================================= // FUNCTION: ClearBuffer() NOT ANSI COMPLIANT! // #include // kbhit(), getch() //========================================================================= // This function clears out the keyboard buffer. void ClearBuffer(void) { while(kbhit()) getch(); // Clear out buffer return; } //========================================================================= // FUNCTION: ClearBuffer() NOT ANSI COMPLIANT! // #include // kbhit() //========================================================================= // This function stalls until a key is hit - does NOT clear buffer first. void WaitForKey(void) { while(!kbhit()); return; } #define DirtyDdotH #endif