summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/pacman/sync.c3
-rw-r--r--src/pacman/util.c108
-rw-r--r--src/pacman/util.h1
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)));