diff --git a/project.yml b/project.yml index e253248..a54e1f4 100644 --- a/project.yml +++ b/project.yml @@ -88,7 +88,7 @@ :placement: :end :flag: "-l${1}" :path_flag: "-L ${1}" - :system: [] # for example, you might list 'm' to grab the math library + :system: [m] # for example, you might list 'm' to grab the math library :test: [] :release: [] diff --git a/src/userinput.c b/src/userinput.c new file mode 100644 index 0000000..cdf03c6 --- /dev/null +++ b/src/userinput.c @@ -0,0 +1,220 @@ +#include "userinput.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define LD(name)\ + long double name##ldvalue;\ + long double *name##ld = NULL;\ + if (name != NULL) {\ + name##ldvalue = *name;\ + name##ld = &name##ldvalue;\ + } + + +void trimLeft(char *input) { + size_t length = strlen(input); + int firstIndex = 0; + while (firstIndex < length && isspace(input[firstIndex])) { + firstIndex++; + } + for (int i = 0; i <= length - firstIndex; i++) { + input[i] = input[firstIndex + i]; + } +} + +void trimRight(char *input) { + size_t length = strlen(input); + int index = length - 1; + while (index >= 0 && isspace(input[index])) { + input[index] = '\0'; + index--; + } +} + +char *readInput() { + size_t bufferSize = 100; + char *buffer = malloc(bufferSize*sizeof(char)); + char c; + int index = 0; + do { + c = fgetc(stdin); + if (!(bufferSize > index)) { + char *newBuffer = malloc(2*bufferSize*sizeof(char)); + for (int i = 0; i < bufferSize; i++) { + newBuffer[i] = buffer[i]; + } + bufferSize *= 2; + } + buffer[index] = c; + index++; + } + while(c != '\n' && c != EOF); + buffer[index - 1] = '\0'; + trimLeft(buffer); + trimRight(buffer); + return buffer; +} + +char *gets(char *message, unsigned long *minLength, unsigned long *maxLength) { + printf("%s", message); + fflush(stdout); + char *result = readInput(); + while (minLength != NULL && strlen(result) < *minLength || maxLength != NULL && strlen(result) > *maxLength) { + printf("%s", "Ungueltige Eingabe! "); + if (minLength != NULL && maxLength == NULL) { + printf("Die Eingabe muss mind. %lu Zeichen lang sein.\n", *minLength); + } + else if (maxLength != NULL && minLength == NULL) { + printf("Die Eingabe darf maximal %lu Zeichen lang sein.\n", *maxLength); + } + else { + printf("Die Eingabe muss %lu bis %lu Zeichen lang sein.\n", *minLength, *maxLength); + } + printf("%s", message); + fflush(stdout); + result = readInput(); + } + return result; +} + +void printlf(long double value) { + if (roundl(value) == value) { + printf("%.0Lf", value); + } + else { + printf("%Lf", value); + } +} + +long double getNumber(char *message, long double *min, long double *max, long double *greaterThan, long double *smallerThan, long double leftBorder, long double rightBorder) { + while (1) { + char *input = gets(message, NULL, NULL); + if (strlen(input) == 0) { + printf("%s\n", "Fehlende Eingabe!"); + fflush(stdout); + free(input); + continue; + } + char *endptr; + long double number = strtold(input, &endptr); + if (strlen(endptr) > 0) { + printf("%s\n", "Ungueltige Eingabe! Gib eine gueltige Zahl ein."); + fflush(stdout); + free(input); + continue; + } + free(input); + bool isValid = true; + if (min != NULL && number < *min) { + isValid = false; + } + if (max != NULL && number > *max) { + isValid = false; + } + if (greaterThan != NULL && !(number > *greaterThan)) { + isValid = false; + } + if (smallerThan != NULL && !(number < *smallerThan)) { + isValid = false; + } + if (number < leftBorder) { + isValid = false; + } + if (number > rightBorder) { + isValid = false; + } + if (isValid) { + return number; + } + printf("Ungueltige Eingabe! Fuer die eingegebene Zahl muss gelten:"); + if (min != NULL) { + printf(" >="); + printlf(*min); + } + if (max != NULL) { + printf(" <="); + printlf(*max); + } + if (greaterThan != NULL) { + printf(" >"); + printlf(*greaterThan); + } + if (smallerThan != NULL) { + printf(" <"); + printlf(*smallerThan); + } + if (min == NULL && greaterThan == NULL) { + printf(" >="); + printlf(leftBorder); + } + if (max == NULL && smallerThan == NULL) { + printf(" <="); + printlf(rightBorder); + } + printf("\n"); + fflush(stdout); + } +} + +short gethd(char *message, short *min, short *max) { + LD(min) + LD(max) + return getNumber(message, minld, maxld, NULL, NULL, SHRT_MIN, SHRT_MAX); +} + +int getd(char *message, int *min, int *max) { + LD(min) + LD(max) + return getNumber(message, minld, maxld, NULL, NULL, INT_MIN, INT_MAX); +} + +long getld(char *message, long *min, long *max) { + LD(min) + LD(max) + return getNumber(message, minld, maxld, NULL, NULL, LONG_MIN, LONG_MAX); +} + +long long getlld(char *message, long long *min, long long *max) { + LD(min) + LD(max) + return getNumber(message, minld, maxld, NULL, NULL, LLONG_MIN, LLONG_MAX); +} + +unsigned short gethu(char *message, unsigned short *min, unsigned short *max) { + LD(min) + LD(max) + return getNumber(message, minld, maxld, NULL, NULL, 0, USHRT_MAX); +} + +unsigned int getu(char *message, unsigned int *min, unsigned int *max) { + LD(min) + LD(max) + return getNumber(message, minld, maxld, NULL, NULL, 0, UINT_MAX); +} + +unsigned long getlu(char *message, unsigned long *min, unsigned long *max) { + LD(min) + LD(max) + return getNumber(message, minld, maxld, NULL, NULL, 0, ULONG_MAX); +} + +unsigned long long getllu(char *message, unsigned long long *min, unsigned long long *max) { + LD(min) + LD(max) + return getNumber(message, minld, maxld, NULL, NULL, 0, ULLONG_MAX); +} + +double getlf(char *message, double *min, double *max, double *greaterThan, double *smallerThan) { + LD(min) + LD(max) + LD(greaterThan) + LD(smallerThan) + return getNumber(message, minld, maxld, greaterThanld, smallerThanld, -DBL_MAX, DBL_MAX); +} \ No newline at end of file diff --git a/src/userinput.h b/src/userinput.h new file mode 100644 index 0000000..9646ad9 --- /dev/null +++ b/src/userinput.h @@ -0,0 +1,79 @@ +#ifndef USERINPUT_H +#define USERINPUT_H + +/// userinput.h provides functions for retrieving user input. +/// The functions are named get + placeholder used by printf for the given datatype. +/// string -> gets +/// short ind -> gethd +/// int -> getd +/// long -> getld +/// long long -> getlld +/// unsigned short -> gethu +/// unsigned int -> getu +/// unsigned long -> getlu +/// unsigned long long -> getllu +/// double -> getlf +/// The provided functions handle validating the user input and ask again for input +/// with the given message until it is valid. + +/// Using the given message gets asks the user to enter a string repeatedly +/// until its length is between minLength and maxLength (both inclusive). +/// The obtained string is then returned. +/// If you don't want to enforce a minLength or a maxLength you can assign it to NULL. +char *gets(char *message, unsigned long *minLength, unsigned long *maxLength); + +/// Using the given message gethd asks the user to enter a short repeatedly +/// until it is in the valid range for a short and between min and max (both inclusive) if provided. +/// The obtained short is then returned. +/// If you don't want to enforce a min or max you can assign it to NULL. +short gethd(char *message, short *min, short *max); + +/// Using the given message getd asks the user to enter an int repeatedly +/// until it is in the valid range for an int and between min and max (both inclusive) if provided. +/// The obtained int is then returned. +/// If you don't want to enforce a min or max you can assign it to NULL. +int getd(char *message, int *min, int *max); + +/// Using the given message getld asks the user to enter a long repeatedly +/// until it is in the valid range for a long and between min and max (both inclusive) if provided. +/// The obtained long is then returned. +/// If you don't want to enforce a min or max you can assign it to NULL. +long getld(char *message, long *min, long *max); + +/// Using the given message getlld asks the user to enter a long long repeatedly +/// until it is in the valid range for a long long and between min and max (both inclusive) if provided. +/// The obtained long is then returned. +/// If you don't want to enforce a min or max you can assign it to NULL. +long long getlld(char *message, long long *min, long long *max); + +/// Using the given message gethu asks the user to enter an unsigned short repeatedly +/// until it is in the valid range for an unsigned short and between min and max (both inclusive) if provided. +/// The obtained unsigned short is then returned. +/// If you don't want to enforce a min or max you can assign it to NULL. +unsigned short gethu(char *message, unsigned short *min, unsigned short *max); + +/// Using the given message getu asks the user to enter an unsigned int repeatedly +/// until it is in the valid range for an unsigned int and between min and max (both inclusive) if provided. +/// The obtained unsigned int is then returned. +/// If you don't want to enforce a min or max you can assign it to NULL. +unsigned int getu(char *message, unsigned int *min, unsigned int *max); + +/// Using the given message getlu asks the user to enter an unsigned long repeatedly +/// until it is in the valid range for an unsigned long and between min and max (both inclusive) if provided. +/// The obtained unsigned long is then returned. +/// If you don't want to enforce a min or max you can assign it to NULL. +unsigned long getlu(char *message, unsigned long *min, unsigned long *max); + +/// Using the given message getllu asks the user to enter an unsigned long long repeatedly +/// until it is in the valid range for an unsigned long long and between min and max (both inclusive) if provided. +/// The obtained unsigned long long is then returned. +/// If you don't want to enforce a min or max you can assign it to NULL. +unsigned long long getllu(char *message, unsigned long long *min, unsigned long long *max); + +/// Using the given message getlf asks the user to enter a double repeatedly +/// until it is in the valid range for a double, between min and max (both inclusive), +/// greater than the given greaterThan and smaller than the given smallerThan. +/// The obtained double is then returned. +/// If you don't want to enforce a min, max, greaterThan or smallerThan you can assign them to NULL. +double getlf(char *message, double *min, double *max, double *greaterThan, double *smallerThan); +#endif