/* utils150.h CIS 150 2008-06-17 David Klick Utility I/O functions used to make programming a little easier and safer. */ #ifndef __UTILS150_H_ #define __UTILS150_H_ #include #include #include #include using std::cout; using std::cin; using std::string; #define UTILS150_OK 0 #define UTILS150_ERR_INVALID_FORMAT 1 #define UTILS150_ERR_BELOW_MIN 2 #define UTILS150_ERR_ABOVE_MAX 3 namespace dgk { /* bool isValidInt(char* str); Arguments: char* str: the address of the C-style string to be checked Returns: true if ptr points to a string which can be interpreted as an integer, otherwise returns false This function takes a C-style string as input and returns true if it represents a valid integer and false if it doesn't. A single leading '+' or '-' is allowed. Leading whitespace is allowed. */ bool isValidInt(char* str) { if (str == NULL) return false; int slen = strlen(str); if (slen == 0) return false; char tmpStr[slen+1]; int tpos = 0; const int ST_INIT = 0; const int ST_SIGN = 1; const int ST_NUM = 2; const int ST_ERR = 3; int state = ST_INIT; char c; char* ptr = str; if (*ptr == '\0') return UTILS150_ERR_INVALID_FORMAT; while ((state != ST_ERR) && (c = *ptr++)) { if (c != ' ' && c != '\t' && c != '+') tmpStr[tpos++] = c; switch (state) { case ST_INIT: if (c == '-' || c == '+') state = ST_SIGN; else if (c == ' ' || c=='\t') state = ST_INIT; else if (c >= '0' && c <= '9') state = ST_NUM; else state = ST_ERR; break; case ST_SIGN: if (c >= '0' && c <= '9') state = ST_NUM; else state = ST_ERR; break; case ST_NUM: if (c >= '0' && c <= '9') state = ST_NUM; else state = ST_ERR; break; default: cout << "Internal state machine error\n"; state = ST_ERR; } } tmpStr[tpos] = '\0'; if (state != ST_NUM) return UTILS150_ERR_INVALID_FORMAT; int tmpval = atoi(str); char tmp[80]; itoa(tmpval, tmp, 10); if (tmpStr[0] == '-' && strcmp(tmp,tmpStr) != 0) return UTILS150_ERR_BELOW_MIN; if (tmpStr[0] != '-' && strcmp(tmp,tmpStr) != 0) return UTILS150_ERR_ABOVE_MAX; if (state == ST_NUM) return UTILS150_OK; else return UTILS150_ERR_INVALID_FORMAT; } /* int getValidInt(char* prompt); Arguments: char* prompt: prompt to display to user Returns: a valid integer entered by the user This function prompts the user and gets an integer from the keyboard. If the value entered is not a valid integer, this routine will discard it and reprompt the user. */ int getValidInt(char* prompt) { char linein[100]; bool valid = false; while (!valid) { cout << prompt; cin.getline(linein, 100, '\n'); int retval = isValidInt(linein); switch (retval) { case UTILS150_OK: valid = true; break; case UTILS150_ERR_INVALID_FORMAT: cout << "Error: Invalid integer number format.\n"; break; case UTILS150_ERR_BELOW_MIN: cout << "Error: Value below minimum integer range.\n"; break; case UTILS150_ERR_ABOVE_MAX: cout << "Error: Value above maximum integer range.\n"; break; } } return atoi(linein); } /* bool isValidFloat(char* ptr); Arguments: char* ptr: the address of the C-style string to be checked Returns: true if ptr points to a string which can be interpreted as a float, otherwise returns false This function takes a C-style string as input and returns true if it represents a valid float and false if it doesn't. A single leading '+' or '-' is allowed. A single decimal point is allowed. */ bool isValidFloat(char* ptr) { char ch; int n = 0; bool hasDecimal = false; // make sure we got a real pointer if (!ptr) return false; // get first character and make sure it exists ch = *ptr++; if (ch == '\0') return false; // allow a leading + or - if (ch=='+' || ch=='-') ch = *ptr++; // make sure all other characters are digits // (also allows a single decimal point) while (ch) { if (ch == '.') { if (hasDecimal) return false; else hasDecimal = true; } else { if (ch<'0' || ch>'9') return false; else n++; // count number of valid digits } ch = *ptr++; } // invalid if no digits present if (n == 0) return false; // if we got here, the number is OK return true; } /* double getValidDouble(char* prompt); Arguments: char* prompt: prompt to display to user Returns: a valid double entered by the user This function prompts the user and gets a double from the keyboard. If the value entered is not a valid double, this routine will discard it and reprompt the user. Scientific notation is not supported, but there may be a single leading sign character (+ or -) and at most one decimal point. */ double getValidDouble(char* prompt) { char buf[40]; double num; bool valid = false; do { cout << prompt; cin.getline(buf, 40, '\n'); if (!isValidFloat(buf)) cout << "Error: Invalid floating point format\n"; else { num = atof(buf); valid = true; } } while (!valid); return num; } /* int getInt(char* msg, int min, int max); Arguments: msg: a pointer to a C-style string to be used as a prompt min: the minimum value allowed to be entered max: the maximum value allowed to be entered Returns: an integer entered by the user Prompts user with message passed in as argument and returns the integer value entered. The number must be between min and max (inclusive) or the user will be reprompted to enter another number. */ int getInt(char* msg, int min = INT_MIN, int max = INT_MAX) { char prompt[strlen(msg) + 40]; sprintf(prompt, "%s (%d - %d): ", msg, min, max); int num; do { num = getValidInt(prompt); if (num < min) cout << "Error: value below minimum allowed\n"; else if (num > max) cout << "Error: value above maximum allowed\n"; } while (nummax); return num; } /* double getDouble(char* msg, double min, double max); Arguments: msg: a pointer to a C-style string to be used as a prompt min: the minimum value allowed to be entered max: the maximum value allowed to be entered Returns: a double entered by the user Prompts user with message passed in as argument and returns the double value entered. The number must be between min and max (inclusive) or the user will be reprompted to enter another number. */ double getDouble(char* msg, double min, double max) { char prompt[strlen(msg) + 40]; sprintf(prompt, "%s (%f - %f): ", msg, min, max); double num; do { num = getValidDouble(prompt); if (num < min) cout << "Error: value below minimum allowed\n"; else if (num > max) cout << "Error: value above maximum allowed\n"; } while (nummax); return num; } } #endif