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

View file

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

View file

@ -1317,6 +1317,13 @@ msgid ""
" --disable-sandbox\n" " --disable-sandbox\n"
" disable the sandbox used for the downloader process\n" " disable the sandbox used for the downloader process\n"
msgstr "" 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 #: src/pacman/pacman.c:249
#, c-format #, c-format
@ -1866,6 +1873,11 @@ msgstr "[J/n]"
msgid "[y/N]" msgid "[y/N]"
msgstr "[j/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 #: src/pacman/util.c:1751
#, c-format #, c-format
msgid "Y" msgid "Y"
@ -1886,6 +1898,11 @@ msgstr "N"
msgid "NO" msgid "NO"
msgstr "NEIN" 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 #: src/pacman/util.c:1820
#, c-format #, c-format
msgid "failed to allocate string\n" msgid "failed to allocate string\n"

View file

@ -1232,6 +1232,11 @@ msgstr ""
" --disable-sandbox\n" " --disable-sandbox\n"
" disable the sandbox used for the downloader process\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 #: src/pacman/pacman.c:249
#, c-format #, c-format
msgid "" msgid ""
@ -1777,6 +1782,10 @@ msgstr "[Y/n]"
msgid "[y/N]" msgid "[y/N]"
msgstr "[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 #: src/pacman/util.c:1751
#, c-format #, c-format
msgid "Y" msgid "Y"
@ -1797,6 +1806,11 @@ msgstr "N"
msgid "NO" msgid "NO"
msgstr "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 #: src/pacman/util.c:1820
#, c-format #, c-format
msgid "failed to allocate string\n" 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))) __attribute__((format(printf, 2, 0)))
static int question(short preset, const char *format, va_list args) static int question(short preset, const char *format, va_list args)
{ {
int return_code = 0;
char response[32]; char response[32];
FILE *stream; FILE *stream;
int fd_in = fileno(stdin); 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) { if(config->noconfirm) {
stream = stdout; stream = stdout;
} else { } else {
@ -1717,12 +1726,61 @@ static int question(short preset, const char *format, va_list args)
stream = stderr; stream = stderr;
} }
/* ensure all text makes it to the screen before we prompt the user */ /* 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);
/* Don't ask me why v*printf() returns an Integer instead of a long */
format_len = vsnprintf(
prompt_cache,
prompt_cache_size,
format, args);
/* 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;
}
/* 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);
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;
}
}
/* We can free the argument-copy now */
va_end(args_copy);
/* 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(stdout);
fflush(stderr); fflush(stderr);
fputs(config->colstr.colon, stream); fputs(config->colstr.colon, stream);
vfprintf(stream, format, args); fputs(prompt_cache, stream);
if(preset) { if(preset) {
fprintf(stream, " %s ", _("[Y/n]")); fprintf(stream, " %s ", _("[Y/n]"));
@ -1743,7 +1801,8 @@ static int question(short preset, const char *format, va_list args)
if(safe_fgets_stdin(response, sizeof(response))) { if(safe_fgets_stdin(response, sizeof(response))) {
size_t len = strtrim(response); size_t len = strtrim(response);
if(len == 0) { if(len == 0) {
return preset; return_code = preset;
goto opt_free_cache;
} }
/* if stdin is piped, response does not get printed out, and as a result /* if stdin is piped, response does not get printed out, and as a result
@ -1753,12 +1812,24 @@ static int question(short preset, const char *format, va_list args)
} }
if(mbscasecmp(response, _("Y")) == 0 || mbscasecmp(response, _("YES")) == 0) { if(mbscasecmp(response, _("Y")) == 0 || mbscasecmp(response, _("YES")) == 0) {
return 1; return_code = 1;
goto opt_free_cache;
} else if(mbscasecmp(response, _("N")) == 0 || mbscasecmp(response, _("NO")) == 0) { } else if(mbscasecmp(response, _("N")) == 0 || mbscasecmp(response, _("NO")) == 0) {
return 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"));
} }
} } while (config->retry_input);
return 0;
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, ...) int yesno(const char *format, ...)