Allow for arbitrary prompts and options in confirm

* Rewrite confirm in c
* Add str_dupe and str_toupper to util.c/util.h
This commit is contained in:
Dylan Lom 2021-04-25 21:00:41 +10:00
parent 9d2ff81c61
commit b3791d5d4d
4 changed files with 98 additions and 26 deletions

78
src/confirm.c Normal file
View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2021 Dylan Lom <djl@dylanlom.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted.
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <strings.h>
#include "util.h"
const char *argv0;
/*
* Display msg, and prompt user for choice from opts.
* Returns index of chosen opt.
*
* First option (opts[0]) is default if nothing else matches
* Comparison is case insensitive
*/
int
confirm(const char *msg, const char **opts, int opts_count)
{
if (opts_count < 2) return 0;
char *opt0 = str_dupe(opts[0], sizeof(opts[0]));
printf("%s [%s", msg, str_toupper(opt0, strlen(opt0)));
free(opt0);
for (int i = 1; i < opts_count; i++) {
printf("/%s", opts[i]);
}
printf("]: ");
char *resp = NULL;
size_t n = 0;
getline(&resp, &n, stdin);
str_trimr(resp, '\n', 1);
for (int i = 0; i < opts_count; i++) {
if (strncasecmp(opts[i], resp, n) == 0) return i;
}
return 0;
}
/*
* Get user confirmation
* Examples:
* $ confirm
* $ confirm "Exit?"
* $ confirm "Download file?" n y
* $ confirm "What color?" red yellow blue
*/
int
main(int argc, const char *argv[])
{
SET_ARGV0();
// Options provided as args
if (argc > 1) return confirm(argv[0], argv+1, argc-1);
const char **opts = STR_EALLOC(2);
opts[0] = "y";
opts[1] = "n";
return confirm(argc == 1 ? argv[0] : "Are you sure?", opts, 2);
}

View File

@ -1,26 +0,0 @@
#!/usr/bin/env sh
#
# confirm: get user confirmation
# author: Dylan Lom <djl@dylanlom.com>
#
# Copyright (C) 2021 Dylan Lom <djl@dylanlom.com>
#
# Permission to use, copy, modify, and/or distribute this software for any purpose
# with or without fee is hereby granted.
#
# 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.
#
truthy "$1" \
&& msg="$1" \
|| msg="Are you sure you want to do that?"
printf "%s [Y/n]: " "$msg"
read resp
test ! "$resp" = 'N' -a ! "$resp" = 'n'

View File

@ -13,6 +13,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdarg.h>
@ -51,6 +52,14 @@ ecalloc(size_t nmemb, size_t size)
return ptr;
}
char *
str_dupe(const char *s, size_t n)
{
char *r = STR_EALLOC(n);
strncpy(r, s, n);
return r;
}
size_t
str_pushc(char *s, char c, size_t s_size, size_t realloc_amount)
{
@ -105,3 +114,12 @@ str_concat(int count, ...)
return new_str;
}
char *
str_toupper(char *s, size_t n)
{
for (size_t i = 0; i < n; i++) {
if islower(s[i]) s[i] = toupper(s[i]);
}
return s;
}

View File

@ -9,8 +9,10 @@ void edie(const char *fmt, ...);
void *ecalloc(size_t nmemb, size_t size);
char *str_dupe(const char *s, size_t n);
size_t str_pushc(char *s, char c, size_t size, size_t realloc_amount);
int str_trimr(char *s, char c, int max_num);
char *str_concat(int count, ...);
char *str_toupper(char *s, size_t n);
#define STR_EALLOC(s) ecalloc((s), sizeof(char))
#define STR_MALLOC(s) calloc((s), sizeof(char))