Skip to content

Instantly share code, notes, and snippets.

@clausecker
Created January 17, 2016 22:27
Show Gist options
  • Save clausecker/0acf1297db0aaf7d902c to your computer and use it in GitHub Desktop.
Save clausecker/0acf1297db0aaf7d902c to your computer and use it in GitHub Desktop.
/*
* yesno.c - Get a yes/no answer from the user
*/
#define _POSIX_C_SOURCE 200809L
#include <langinfo.h>
#include <regex.h>
#include <stdio.h>
/*
* Return values of yesno()
*/
enum {
YN_YES = 0, /* affirmative response */
YN_NO = 1, /* negative response */
YN_RETRY = 2, /* neither affirmative nor negative */
YN_ERROR = -1 /* an error occured */
};
/*
* Compile the regular expression expr, if that fails, compile expr2
* instead. Print an error message if compiling either failed. Return
* 0 on success, -1 on failure.
*/
static int
regex_helper(regex_t *restrict regex, const char *restrict expr, const char *restrict expr2)
{
int compresult;
static char errorbuf[256];
compresult = regcomp(regex, expr, REG_NOSUB);
if (compresult == 0)
return 0;
/* try to print an error message */
regerror(compresult, regex, errorbuf, sizeof errorbuf);
fprintf(stderr, "Error compiling regular expression %s: %s", expr, errorbuf);
if (expr2 != NULL)
return (regex_helper(regex, expr2, NULL));
else
return (-1);
}
/*
* Get a line of text from stdin and compare it against YESEXPR and
* NOEXPR. If one of them matches, return YN_YES or YN_NO. If neither
* matches, return YN_RETRY. If an error occurs, return YN_ERROR.
* An error message will be printed in this case, the value of errno
* is not significant.
*/
extern int
yesno(void)
{
static regex_t yesregex, noregex;
static size_t inputlen = 0;
static int haveyes = 0, haveno = 0;
static char *inputbuf = NULL;
/* use POSIX-locale expressions as fallback */
if (!haveyes && regex_helper(&yesregex, nl_langinfo(YESEXPR), "^[yY]"))
return (YN_ERROR);
else
haveyes = 1;
if (!haveno && regex_helper(&noregex, nl_langinfo(NOEXPR), "^[nN]"))
return (YN_ERROR);
else
haveno = 1;
if (getline(&inputbuf, &inputlen, stdin) < 0) {
if (ferror(stdin))
perror("Error reading stdin");
else
fprintf(stderr, "End of file on stdin");
return (YN_ERROR);
}
if (regexec(&yesregex, inputbuf, 0, NULL, 0) == 0)
return (YN_YES);
if (regexec(&noregex, inputbuf, 0, NULL, 0) == 0)
return (YN_NO);
return (YN_RETRY);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment