From 00fec5e2503a8272ebac9f240e03d655131ec216 Mon Sep 17 00:00:00 2001 From: Xavier Chantry Date: Sun, 17 Oct 2010 17:09:25 +0200 Subject: pacman/sync: implement interactive group selection Signed-off-by: Xavier Chantry --- src/pacman/sync.c | 3 +- src/pacman/util.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/pacman/util.h | 1 + 3 files changed, 110 insertions(+), 2 deletions(-) diff --git a/src/pacman/sync.c b/src/pacman/sync.c index 63e5766e..1e622d37 100644 --- a/src/pacman/sync.c +++ b/src/pacman/sync.c @@ -636,9 +636,8 @@ static int process_group(alpm_list_t *dbs, char *group) printf(_(":: There are %d members in group %s:\n"), count, group); select_display(pkgs); - select_question(count); char *array = malloc(count); - memset(array, 1, count); + multiselect_question(array, count); int n = 0; for(i = pkgs; i; i = alpm_list_next(i)) { if(array[n++] == 0) diff --git a/src/pacman/util.c b/src/pacman/util.c index 133dccc2..51abbf4d 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -694,6 +694,114 @@ void select_display(const alpm_list_t *pkglist) FREELIST(list); } +static int parseindex(char *s, int *val, int min, int max) +{ + char *endptr = NULL; + int n = strtol(s, &endptr, 10); + if(*endptr == '\0') { + if(n < min || n > max) { + fprintf(stderr, _("Invalid value: %d is not between %d and %d\n"), + n, min, max); + return(-1); + } + *val = n; + return(0); + } else { + fprintf(stderr, _("Invalid number: %s\n"), s); + return(-1); + } +} + +static int multiselect_parse(char *array, int count, char *response) +{ + char *str, *saveptr; + + for (str = response; ; str = NULL) { + int include = 1; + int start, end; + char *ends = NULL; + char *starts = strtok_r(str, " ", &saveptr); + + if (starts == NULL) + break; + strtrim(starts); + int len = strlen(starts); + if(len == 0) + continue; + + if (*starts == '^') { + starts++; + len--; + include = 0; + } else if(str) { + /* if first token is including, we unselect all targets */ + memset(array, 0, count); + } + + if(len > 1) { + /* check for range */ + char *p; + if((p = strchr(starts+1, '-'))) { + *p = 0; + ends = p+1; + } + } + + if(parseindex(starts, &start, 1, count) != 0) + return(-1); + + if(!ends) { + array[start-1] = include; + } else { + if(parseindex(ends, &end, start, count) != 0) + return(-1); + for(int d = start; d <= end; d++) { + array[d-1] = include; + } + } + } + + return(0); +} + +int multiselect_question(char *array, int count) +{ + char response[64]; + FILE *stream; + + if(config->noconfirm) { + stream = stdout; + } else { + /* Use stderr so questions are always displayed when redirecting output */ + stream = stderr; + } + + while(1) { + memset(array, 1, count); + + fprintf(stream, "\n"); + fprintf(stream, _("Enter a selection (default=all)")); + fprintf(stream, ": "); + + if(config->noconfirm) { + fprintf(stream, "\n"); + break; + } + + if(fgets(response, sizeof(response), stdin)) { + strtrim(response); + if(strlen(response) > 0) { + if(multiselect_parse(array, count, response) == -1) { + /* only loop if user gave an invalid answer */ + continue; + } + } + } + break; + } + return(0); +} + int select_question(int count) { char response[32]; diff --git a/src/pacman/util.h b/src/pacman/util.h index 399f9bc8..234a631d 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -61,6 +61,7 @@ void display_optdepends(pmpkg_t *pkg); void print_packages(const alpm_list_t *packages); void select_display(const alpm_list_t *pkglist); int select_question(int count); +int multiselect_question(char *array, int count); int yesno(char *fmt, ...); int noyes(char *fmt, ...); int pm_printf(pmloglevel_t level, const char *format, ...) __attribute__((format(printf,2,3))); -- cgit v1.2.3-24-g4f1b