diff --git a/README.md b/README.md index 3158593..c63f1e3 100644 --- a/README.md +++ b/README.md @@ -308,6 +308,11 @@ Generic Functions **Note:** `which("/bin/ps aux")` will return `/bin/ps`, or `TRUE`, provided of course `/bin/ps` exists. +- `yorn(fmt, ...)` + + Pose a question to user, appended with `(y/N)?`, returns `TRUE` for + yes (both `y` and `Y` are handled) and `FALSE` for everything else. + GNU Functions ------------- diff --git a/src/Makefile.am b/src/Makefile.am index b6401ce..1167432 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,7 +14,7 @@ libite_la_SOURCES = chomp.c copyfile.c \ reallocarray.c rsync.c \ strlcpy.c strlcat.c strtonum.c \ strdupa.h strndupa.h strnlen.h \ - strmatch.c \ + strmatch.c yorn.c \ tempfile.c which.c \ lite.h strlite.h \ queue.h tree.h @@ -22,4 +22,5 @@ libite_la_SOURCES = chomp.c copyfile.c \ ## Distribute these header files in the name space pkgincludedir = $(includedir)/lite -pkginclude_HEADERS = lite.h queue.h conio.h tree.h strlite.h strdupa.h strndupa.h strnlen.h +pkginclude_HEADERS = lite.h queue.h conio.h tree.h strlite.h strdupa.h \ + strndupa.h strnlen.h diff --git a/src/lite.h b/src/lite.h index ea4fdeb..14f744a 100644 --- a/src/lite.h +++ b/src/lite.h @@ -95,6 +95,8 @@ void *reallocarray(void *optr, size_t nmemb, size_t size); void progress (int percent, int max_width); void progress_simple(int percent); +int yorn (const char *fmt, ...); + char *which (const char *cmd); int whichp (const char *cmd); diff --git a/src/yorn.c b/src/yorn.c new file mode 100644 index 0000000..af7b186 --- /dev/null +++ b/src/yorn.c @@ -0,0 +1,92 @@ +/* Safe yes-or-no with prompt + * + * Copyright (c) 2009 Joachim Nilsson + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include /* __fpurge() */ +#include +#include +#include + +static char rawgetch(void) +{ + struct termios savemodes, modmodes; + char val; + + if (!isatty(STDIN_FILENO)) + return getchar(); + + /* Backup terminal settings. */ + if (tcgetattr(STDIN_FILENO, &savemodes) < 0) { + return -1; + } + + /* "stty cbreak -echo" */ + modmodes = savemodes; + modmodes.c_lflag &= ~ICANON; + modmodes.c_lflag &= ~ECHO; + modmodes.c_cc[VMIN] = 1; + modmodes.c_cc[VTIME] = 0; + + /* Set terminal in raw mode. */ + if (tcsetattr(STDIN_FILENO, TCSANOW, &modmodes) < 0) { + tcsetattr(STDIN_FILENO, TCSANOW, &savemodes); + return -1; + } + + val = getchar(); + + /* Restore terminal to previous state. */ + tcsetattr(STDIN_FILENO, TCSANOW, &savemodes); + + return val; +} + +/** + * yorn - Pose a a Yes or No question and return answer + * @fmt: Standard printf() style argument(s). + * + * This function prints the given question on screen, waits for user + * input in the form of yes or no. + * + * Returns: + * True(1) or False(0). True if the answer is yes. + */ +int yorn(const char *fmt, ...) +{ + va_list ap; + char yorn; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + __fpurge(stdin); + yorn = rawgetch(); + printf("%c\n", yorn); + fflush(stdout); + if (yorn != 'y' && yorn != 'Y') + return 0; + + return 1; +} + +/** + * Local Variables: + * indent-tabs-mode: t + * c-file-style: "linux" + * End: + */ diff --git a/tests/.gitignore b/tests/.gitignore index 3ba0413..75fafd0 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -17,3 +17,4 @@ tempfile touch tree which +yorn diff --git a/tests/Makefile.am b/tests/Makefile.am index fbe3815..326a0e6 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -18,6 +18,7 @@ TESTS += strmatch TESTS += touch TESTS += tempfile TESTS += which +TESTS += yorn check_PROGRAMS = $(TESTS) diff --git a/tests/yorn.c b/tests/yorn.c new file mode 100644 index 0000000..bf80a15 --- /dev/null +++ b/tests/yorn.c @@ -0,0 +1,32 @@ +#include +#include +#include + +#include "check.h" + +int main(int argc, char *argv[]) +{ + int chan[2]; + int status; + + pipe(chan); + + if (fork() > 0) { + dup2(chan[0], STDIN_FILENO); + if (yorn("Do you really wanna do this (y/N)? ")) { + printf("Affirmative!\n"); + _exit(0); + } + + printf("OK, aborting!\n"); + _exit(1); + } + + sleep(1); + if (write(chan[1], "Y", 1) != 1) + return 1; + + wait(&status); + + return WEXITSTATUS(status); +}