Merge branch 'retry-prompt' into 'master'

Add `--retry-prompt` to make `Y/N`-prompts more uniform to other prompts.

See merge request pacman/pacman!221
This commit is contained in:
Not Important 2025-06-26 20:59:36 +00:00
commit 39b47ceec8
5 changed files with 139 additions and 30 deletions

View file

@ -59,6 +59,7 @@ typedef struct __config_t {
unsigned short color;
unsigned short disable_dl_timeout;
unsigned short disable_sandbox;
unsigned short retry_input;
char *print_format;
/* unfortunately, we have to keep track of paths both here and in the library
* because they can come from both the command line or config file, and we
@ -214,7 +215,8 @@ enum {
OP_REFRESH,
OP_ASSUMEINSTALLED,
OP_DISABLEDLTIMEOUT,
OP_DISABLESANDBOX
OP_DISABLESANDBOX,
OP_RETRYINPUT
};
/* clean method */

View file

@ -228,6 +228,7 @@ static void usage(int op, const char * const myname)
" use relaxed timeouts for download\n"));
addlist(_(" --disable-sandbox\n"
" disable the sandbox used for the downloader process\n"));
addlist(_(" --retry-prompt repeat prompts until a valid answer is supplied\n"));
}
list = alpm_list_msort(list, alpm_list_count(list), options_cmp);
for(i = list; i; i = alpm_list_next(i)) {
@ -499,6 +500,9 @@ static int parsearg_global(int opt)
case 'v':
(config->verbose)++;
break;
case OP_RETRYINPUT:
config->retry_input = 1;
break;
default:
return 1;
}
@ -982,6 +986,7 @@ static int parseargs(int argc, char *argv[])
{"color", required_argument, 0, OP_COLOR},
{"disable-download-timeout", no_argument, 0, OP_DISABLEDLTIMEOUT},
{"disable-sandbox", no_argument, 0, OP_DISABLESANDBOX},
{"retry-prompt", no_argument, 0, OP_RETRYINPUT},
{0, 0, 0, 0}
};

View file

@ -1317,6 +1317,13 @@ msgid ""
" --disable-sandbox\n"
" disable the sandbox used for the downloader process\n"
msgstr ""
" --disable-sandbox\n"
" shaltet Sandbox für den Download-Prozess aus\n"
#: src/pacman/pacman.c:231
#, c-format
msgid " --retry-prompt repeat prompts until a valid answer is supplied\n"
msgstr " --retry-prompt wiederholt Frage, bis eine valide Antwort gegeben wird\n"
#: src/pacman/pacman.c:249
#, c-format
@ -1866,6 +1873,11 @@ msgstr "[J/n]"
msgid "[y/N]"
msgstr "[j/N]"
#: src/pacman/util.c:1741
#, c-format
msgid "vsnprintf failure: Failed to cache prompt: %s\n"
msgstr "vsnprintf-fehler: Kann Frage nicht cachen: %s\n"
#: src/pacman/util.c:1751
#, c-format
msgid "Y"
@ -1886,6 +1898,11 @@ msgstr "N"
msgid "NO"
msgstr "NEIN"
#: src/pacman/util.c:1769
#, c-format
msgid "vsnprintf failure: Failed to cache prompt: Required size changed: %zu -> %i bytes\n"
msgstr "vsnprintf-fehler: Kann Frage nicht cachen: Benötigte Größe hat sich geändert: %zu -> %i bytes\n"
#: src/pacman/util.c:1820
#, c-format
msgid "failed to allocate string\n"

View file

@ -1232,6 +1232,11 @@ msgstr ""
" --disable-sandbox\n"
" disable the sandbox used for the downloader process\n"
#: src/pacman/pacman.c:231
#, c-format
msgid " --retry-prompt repeat prompts until a valid answer is supplied\n"
msgstr " --retry-prompt repeat prompts until a valid answer is supplied\n"
#: src/pacman/pacman.c:249
#, c-format
msgid ""
@ -1777,6 +1782,10 @@ msgstr "[Y/n]"
msgid "[y/N]"
msgstr "[y/N]"
#: src/pacman/util.c:1741 src/pacman/util.c:1759
msgid "vsnprintf failure: Failed to cache prompt: %s\n"
msgstr "vsnprintf failure: Failed to cache prompt: %s\n"
#: src/pacman/util.c:1751
#, c-format
msgid "Y"
@ -1797,6 +1806,11 @@ msgstr "N"
msgid "NO"
msgstr "NO"
#: src/pacman/util.c:1767
#, c-format
msgid "vsnprintf failure: Failed to cache prompt: Required size changed: %zu -> %i bytes\n"
msgstr "vsnprintf failure: Failed to cache prompt: Required size changed: %zu -> %i bytes\n"
#: src/pacman/util.c:1820
#, c-format
msgid "failed to allocate string\n"

View file

@ -1706,10 +1706,19 @@ static int mbscasecmp(const char *s1, const char *s2)
__attribute__((format(printf, 2, 0)))
static int question(short preset, const char *format, va_list args)
{
int return_code = 0;
char response[32];
FILE *stream;
int fd_in = fileno(stdin);
va_list args_copy;
int format_len;
/* No need to initialize:
* the other calls also print a termination character */
char prompt_cache_stack[256];
char *prompt_cache = prompt_cache_stack;
size_t prompt_cache_size = sizeof(prompt_cache_stack);
if(config->noconfirm) {
stream = stdout;
} else {
@ -1717,48 +1726,110 @@ static int question(short preset, const char *format, va_list args)
stream = stderr;
}
/* ensure all text makes it to the screen before we prompt the user */
fflush(stdout);
fflush(stderr);
/* Cache prompt, because we can't call v*printf() multiple times
* on the same arguments. */
/* Copy args so we can retry when the buffer is too small */
va_copy(args_copy, args);
fputs(config->colstr.colon, stream);
vfprintf(stream, format, args);
/* Don't ask me why v*printf() returns an Integer instead of a long */
format_len = vsnprintf(
prompt_cache,
prompt_cache_size,
format, args);
if(preset) {
fprintf(stream, " %s ", _("[Y/n]"));
} else {
fprintf(stream, " %s ", _("[y/N]"));
/* Something has gone wrong */
if (format_len < 1) {
pm_printf(ALPM_LOG_ERROR, _("vsnprintf failure: Failed to cache prompt: %s\n"), strerror(errno));
goto free_args_copy;
}
fputs(config->colstr.nocolor, stream);
fflush(stream);
/* Buffer is too small */
if ((size_t)format_len + 1 > prompt_cache_size) {
prompt_cache = malloc(format_len + 1);
prompt_cache_size = format_len + 1;
if (prompt_cache == 0) {
pm_printf(ALPM_LOG_ERROR, _("malloc failure: could not allocate %i bytes\n"), format_len + 1);
if(config->noconfirm) {
fprintf(stream, "\n");
return preset;
goto free_args_copy;
}
format_len = vsnprintf(prompt_cache, prompt_cache_size, format, args_copy);
/* Something has gone wrong */
if (format_len < 1) {
pm_printf(ALPM_LOG_ERROR, _("vsnprintf failure: Failed to cache prompt: %s\n"), strerror(errno));
goto free_args_copy;
}
/* Just in case */
if ((size_t)format + 1 != prompt_cache_size) {
pm_printf(ALPM_LOG_ERROR, _("vsnprintf failure: Failed to cache prompt: Required size changed: %zu -> %i bytes\n"), prompt_cache_size, format_len + 1);
goto free_args_copy;
}
}
flush_term_input(fd_in);
/* We can free the argument-copy now */
va_end(args_copy);
if(safe_fgets_stdin(response, sizeof(response))) {
size_t len = strtrim(response);
if(len == 0) {
/* Prompt the user at least once before exiting */
do {
/* Ensure all text makes it to the screen before we prompt the user */
fflush(stdout);
fflush(stderr);
fputs(config->colstr.colon, stream);
fputs(prompt_cache, stream);
if(preset) {
fprintf(stream, " %s ", _("[Y/n]"));
} else {
fprintf(stream, " %s ", _("[y/N]"));
}
fputs(config->colstr.nocolor, stream);
fflush(stream);
if(config->noconfirm) {
fprintf(stream, "\n");
return preset;
}
/* if stdin is piped, response does not get printed out, and as a result
* a \n is missing, resulting in broken output */
if(!isatty(fd_in)) {
fprintf(stream, "%s\n", response);
}
flush_term_input(fd_in);
if(mbscasecmp(response, _("Y")) == 0 || mbscasecmp(response, _("YES")) == 0) {
return 1;
} else if(mbscasecmp(response, _("N")) == 0 || mbscasecmp(response, _("NO")) == 0) {
return 0;
if(safe_fgets_stdin(response, sizeof(response))) {
size_t len = strtrim(response);
if(len == 0) {
return_code = preset;
goto opt_free_cache;
}
/* if stdin is piped, response does not get printed out, and as a result
* a \n is missing, resulting in broken output */
if(!isatty(fd_in)) {
fprintf(stream, "%s\n", response);
}
if(mbscasecmp(response, _("Y")) == 0 || mbscasecmp(response, _("YES")) == 0) {
return_code = 1;
goto opt_free_cache;
} else if(mbscasecmp(response, _("N")) == 0 || mbscasecmp(response, _("NO")) == 0) {
goto opt_free_cache;
} else
/* Emulate same behaviour as multiselect_question() and select_question() */
fprintf(stream, _("invalid input: prompt requires `%s' or `%s'\n\n"), _("Y"), _("N"));
}
}
return 0;
} while (config->retry_input);
opt_free_cache:
if (prompt_cache != prompt_cache_stack)
free(prompt_cache);
return return_code;
free_args_copy:
va_end(args_copy);
return return_code;
}
int yesno(const char *format, ...)