1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
#include "get_input.h"
#include <assert.h>
#ifndef _GET_INPUT_C
# define _GET_INPUT_C
#endif
/* gi_get_opts: fill optstring with options based on an object of struct opts
* opts: a const array object of struct opts from which to get options and
* the default option.
* optstring: a C-string into which the options will be placed, in the format
* [option1/option2/option3] (with up to n options)
* n: the amount of options to be found in opts and placed in optstring
* Note: this routine should not be called directly, and is therefore static.
*/
static
char* gi_get_opts(const struct gi_options opts[], char* optstring, size_t n) {
int i = 0;
size_t string_sz_sum = 0;
/* Sum the lengths of all the options in opts */
for (; i < n; i++)
string_sz_sum += strlen(opts[i].option);
/* Allocate optstring enough memory to store all the options,
* the enclosing brackets, and a forward-slash between each option */
const size_t optstring_sz = 1 + string_sz_sum + n + 1 + 1;
/* [ + options + n + ] + \0 */
optstring = (char*)malloc(optstring_sz);
if (!optstring)
fprintf(stderr, "Couldn't allocate %ld bytes of memory\n", optstring_sz);
memset(optstring, 0, optstring_sz);
optstring[0] = '['; /* For the enclosing bracket */
/* Concatenate the options into optstring */
for (i = 0; i < n; i++) {
strcat(optstring, opts[i].option);
if ((i + 1) < n)
strcat(optstring, "/");
}
optstring[optstring_sz - 3] = ']';
return optstring;
}
/* gi_get_buf: fill buf with validated user input from stdin
* buf: a buffer into which user input will be placed
* bufsz: the given size of buf
* prompt: the prompt to be displayed
* optstring: a string of options to search
* Note: this routine should not be called directly, and is therefore static.
*/
static
char* gi_get_buf(char* buf, size_t bufsz, const char* prompt,
const char* optstring, struct gi_options opts[], size_t n) {
int i = 0;
do {
printf("%s%s: ", (i > 0) ? "\nInvalid input. " : "", prompt);
fgets(buf, bufsz, stdin);
buf[strlen(buf) - 1] = 0;
i++;
} while ((strstr(optstring, buf)) && strcmp(buf, "\n"));
/* This is done to validate buf: if the option isn't in optstring,
* the caller doesn't want it as input */
if (strcmp(buf, "\n") == 0) { /* Default option is to be used */
while (n--)
if (opts[n].is_default == 1)
break;
strcpy(buf, opts[n].option);
}
return buf;
}
/* get_input: get input from the user with up to n options
* buf: buffer to store the input from the user in. It should be noted that
* get_input null-terminates buf.
* prompt: prompt to display to the user
* options: an object of struct gi_options with n elements to be displayed
* as options
* n: the amount of options chosen to be displayed,
* should be equal to the amount of elements in options
* bufsz: the size (bytes) that buf can store
*/
char* get_input(char* buf, const char* prompt,
struct gi_options opts[], size_t n, size_t bufsz) {
char* optstring = NULL,
* promptBuf = NULL;
if (!gi_get_opts(opts, optstring, n))
return NULL;
/* Allocate promptBuf with enough data to store optstring and prompt */
promptBuf = (char*)malloc(strlen(prompt) + strlen(optstring) + 3);
strcpy(promptBuf, prompt);
strcat(promptBuf, " ");
strcat(promptBuf, optstring);
/* Now we've built a prompt, we can take the input */
if (!gi_get_buf(buf, bufsz, promptBuf, optstring, opts, n))
return NULL;
free(optstring);
free(promptBuf);
return buf;
}
|