Merge branch 'rs/clean-menu-item-defn'
authorJunio C Hamano <gitster@pobox.com>
Tue, 9 Sep 2014 19:54:06 +0000 (12:54 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 9 Sep 2014 19:54:06 +0000 (12:54 -0700)
* rs/clean-menu-item-defn:
clean: use f(void) instead of f() to declare a pointer to a function without arguments

1  2 
builtin/clean.c
diff --combined builtin/clean.c
index 1032563e5fae880df9256c9eafaa96d60462ecd2,95b41279c0dcc6781e210519183090d38d54c77a..3beeea6ec0fdc3883f2456caf46f3e1c4dadc682
@@@ -15,7 -15,6 +15,7 @@@
  #include "quote.h"
  #include "column.h"
  #include "color.h"
 +#include "pathspec.h"
  
  static int force = -1; /* unset */
  static int interactive;
@@@ -48,7 -47,7 +48,7 @@@ enum color_clean 
        CLEAN_COLOR_PROMPT = 2,
        CLEAN_COLOR_HEADER = 3,
        CLEAN_COLOR_HELP = 4,
 -      CLEAN_COLOR_ERROR = 5,
 +      CLEAN_COLOR_ERROR = 5
  };
  
  #define MENU_OPTS_SINGLETON           01
@@@ -67,7 -66,7 +67,7 @@@ struct menu_item 
        char hotkey;
        const char *title;
        int selected;
-       int (*fn)();
+       int (*fn)(void);
  };
  
  enum menu_stuff_type {
@@@ -100,7 -99,7 +100,7 @@@ static int parse_clean_color_slot(cons
  
  static int git_clean_config(const char *var, const char *value, void *cb)
  {
 -      if (!prefixcmp(var, "column."))
 +      if (starts_with(var, "column."))
                return git_column_config(var, value, "clean", &colopts);
  
        /* honors the color.interactive* config variables which also
                clean_use_color = git_config_colorbool(var, value);
                return 0;
        }
 -      if (!prefixcmp(var, "color.interactive.")) {
 +      if (starts_with(var, "color.interactive.")) {
                int slot = parse_clean_color_slot(var +
                                                  strlen("color.interactive."));
                if (slot < 0)
@@@ -154,7 -153,7 +154,7 @@@ static int remove_dirs(struct strbuf *p
        DIR *dir;
        struct strbuf quoted = STRBUF_INIT;
        struct dirent *e;
 -      int res = 0, ret = 0, gone = 1, original_len = path->len, len, i;
 +      int res = 0, ret = 0, gone = 1, original_len = path->len, len;
        unsigned char submodule_head[20];
        struct string_list dels = STRING_LIST_INIT_DUP;
  
        }
  
        if (!*dir_gone && !quiet) {
 +              int i;
                for (i = 0; i < dels.nr; i++)
                        printf(dry_run ?  _(msg_would_remove) : _(msg_remove), dels.items[i].string);
        }
@@@ -367,56 -365,6 +367,56 @@@ static void print_highlight_menu_stuff(
        string_list_clear(&menu_list, 0);
  }
  
 +static int find_unique(const char *choice, struct menu_stuff *menu_stuff)
 +{
 +      struct menu_item *menu_item;
 +      struct string_list_item *string_list_item;
 +      int i, len, found = 0;
 +
 +      len = strlen(choice);
 +      switch (menu_stuff->type) {
 +      default:
 +              die("Bad type of menu_stuff when parse choice");
 +      case MENU_STUFF_TYPE_MENU_ITEM:
 +
 +              menu_item = (struct menu_item *)menu_stuff->stuff;
 +              for (i = 0; i < menu_stuff->nr; i++, menu_item++) {
 +                      if (len == 1 && *choice == menu_item->hotkey) {
 +                              found = i + 1;
 +                              break;
 +                      }
 +                      if (!strncasecmp(choice, menu_item->title, len)) {
 +                              if (found) {
 +                                      if (len == 1) {
 +                                              /* continue for hotkey matching */
 +                                              found = -1;
 +                                      } else {
 +                                              found = 0;
 +                                              break;
 +                                      }
 +                              } else {
 +                                      found = i + 1;
 +                              }
 +                      }
 +              }
 +              break;
 +      case MENU_STUFF_TYPE_STRING_LIST:
 +              string_list_item = ((struct string_list *)menu_stuff->stuff)->items;
 +              for (i = 0; i < menu_stuff->nr; i++, string_list_item++) {
 +                      if (!strncasecmp(choice, string_list_item->string, len)) {
 +                              if (found) {
 +                                      found = 0;
 +                                      break;
 +                              }
 +                              found = i + 1;
 +                      }
 +              }
 +              break;
 +      }
 +      return found;
 +}
 +
 +
  /*
   * Parse user input, and return choice(s) for menu (menu_stuff).
   *
@@@ -444,6 -392,8 +444,6 @@@ static int parse_choice(struct menu_stu
                        int **chosen)
  {
        struct strbuf **choice_list, **ptr;
 -      struct menu_item *menu_item;
 -      struct string_list_item *string_list_item;
        int nr = 0;
        int i;
  
                        bottom = 1;
                        top = menu_stuff->nr;
                } else {
 -                      switch (menu_stuff->type) {
 -                      default:
 -                              die("Bad type of menu_stuff when parse choice");
 -                      case MENU_STUFF_TYPE_MENU_ITEM:
 -                              menu_item = (struct menu_item *)menu_stuff->stuff;
 -                              for (i = 0; i < menu_stuff->nr; i++, menu_item++) {
 -                                      if (((*ptr)->len == 1 &&
 -                                           *(*ptr)->buf == menu_item->hotkey) ||
 -                                          !strcasecmp((*ptr)->buf, menu_item->title)) {
 -                                              bottom = i + 1;
 -                                              top = bottom;
 -                                              break;
 -                                      }
 -                              }
 -                              break;
 -                      case MENU_STUFF_TYPE_STRING_LIST:
 -                              string_list_item = ((struct string_list *)menu_stuff->stuff)->items;
 -                              for (i = 0; i < menu_stuff->nr; i++, string_list_item++) {
 -                                      if (!strcasecmp((*ptr)->buf, string_list_item->string)) {
 -                                              bottom = i + 1;
 -                                              top = bottom;
 -                                              break;
 -                                      }
 -                              }
 -                              break;
 -                      }
 +                      bottom = find_unique((*ptr)->buf, menu_stuff);
 +                      top = bottom;
                }
  
                if (top <= 0 || bottom <= 0 || top > menu_stuff->nr || bottom > top ||
@@@ -621,7 -595,8 +621,7 @@@ static int *list_and_choose(struct menu
                                nr += chosen[i];
                }
  
 -              result = xmalloc(sizeof(int) * (nr + 1));
 -              memset(result, 0, sizeof(int) * (nr + 1));
 +              result = xcalloc(nr + 1, sizeof(int));
                for (i = 0; i < stuff->nr && j < nr; i++) {
                        if (chosen[i])
                                result[j++] = i;
@@@ -639,143 -614,6 +639,143 @@@ static int clean_cmd(void
        return MENU_RETURN_NO_LOOP;
  }
  
 +static int filter_by_patterns_cmd(void)
 +{
 +      struct dir_struct dir;
 +      struct strbuf confirm = STRBUF_INIT;
 +      struct strbuf **ignore_list;
 +      struct string_list_item *item;
 +      struct exclude_list *el;
 +      int changed = -1, i;
 +
 +      for (;;) {
 +              if (!del_list.nr)
 +                      break;
 +
 +              if (changed)
 +                      pretty_print_dels();
 +
 +              clean_print_color(CLEAN_COLOR_PROMPT);
 +              printf(_("Input ignore patterns>> "));
 +              clean_print_color(CLEAN_COLOR_RESET);
 +              if (strbuf_getline(&confirm, stdin, '\n') != EOF)
 +                      strbuf_trim(&confirm);
 +              else
 +                      putchar('\n');
 +
 +              /* quit filter_by_pattern mode if press ENTER or Ctrl-D */
 +              if (!confirm.len)
 +                      break;
 +
 +              memset(&dir, 0, sizeof(dir));
 +              el = add_exclude_list(&dir, EXC_CMDL, "manual exclude");
 +              ignore_list = strbuf_split_max(&confirm, ' ', 0);
 +
 +              for (i = 0; ignore_list[i]; i++) {
 +                      strbuf_trim(ignore_list[i]);
 +                      if (!ignore_list[i]->len)
 +                              continue;
 +
 +                      add_exclude(ignore_list[i]->buf, "", 0, el, -(i+1));
 +              }
 +
 +              changed = 0;
 +              for_each_string_list_item(item, &del_list) {
 +                      int dtype = DT_UNKNOWN;
 +
 +                      if (is_excluded(&dir, item->string, &dtype)) {
 +                              *item->string = '\0';
 +                              changed++;
 +                      }
 +              }
 +
 +              if (changed) {
 +                      string_list_remove_empty_items(&del_list, 0);
 +              } else {
 +                      clean_print_color(CLEAN_COLOR_ERROR);
 +                      printf_ln(_("WARNING: Cannot find items matched by: %s"), confirm.buf);
 +                      clean_print_color(CLEAN_COLOR_RESET);
 +              }
 +
 +              strbuf_list_free(ignore_list);
 +              clear_directory(&dir);
 +      }
 +
 +      strbuf_release(&confirm);
 +      return 0;
 +}
 +
 +static int select_by_numbers_cmd(void)
 +{
 +      struct menu_opts menu_opts;
 +      struct menu_stuff menu_stuff;
 +      struct string_list_item *items;
 +      int *chosen;
 +      int i, j;
 +
 +      menu_opts.header = NULL;
 +      menu_opts.prompt = N_("Select items to delete");
 +      menu_opts.flags = 0;
 +
 +      menu_stuff.type = MENU_STUFF_TYPE_STRING_LIST;
 +      menu_stuff.stuff = &del_list;
 +      menu_stuff.nr = del_list.nr;
 +
 +      chosen = list_and_choose(&menu_opts, &menu_stuff);
 +      items = del_list.items;
 +      for (i = 0, j = 0; i < del_list.nr; i++) {
 +              if (i < chosen[j]) {
 +                      *(items[i].string) = '\0';
 +              } else if (i == chosen[j]) {
 +                      /* delete selected item */
 +                      j++;
 +                      continue;
 +              } else {
 +                      /* end of chosen (chosen[j] == EOF), won't delete */
 +                      *(items[i].string) = '\0';
 +              }
 +      }
 +
 +      string_list_remove_empty_items(&del_list, 0);
 +
 +      free(chosen);
 +      return 0;
 +}
 +
 +static int ask_each_cmd(void)
 +{
 +      struct strbuf confirm = STRBUF_INIT;
 +      struct strbuf buf = STRBUF_INIT;
 +      struct string_list_item *item;
 +      const char *qname;
 +      int changed = 0, eof = 0;
 +
 +      for_each_string_list_item(item, &del_list) {
 +              /* Ctrl-D should stop removing files */
 +              if (!eof) {
 +                      qname = quote_path_relative(item->string, NULL, &buf);
 +                      printf(_("remove %s? "), qname);
 +                      if (strbuf_getline(&confirm, stdin, '\n') != EOF) {
 +                              strbuf_trim(&confirm);
 +                      } else {
 +                              putchar('\n');
 +                              eof = 1;
 +                      }
 +              }
 +              if (!confirm.len || strncasecmp(confirm.buf, "yes", confirm.len)) {
 +                      *item->string = '\0';
 +                      changed++;
 +              }
 +      }
 +
 +      if (changed)
 +              string_list_remove_empty_items(&del_list, 0);
 +
 +      strbuf_release(&buf);
 +      strbuf_release(&confirm);
 +      return MENU_RETURN_NO_LOOP;
 +}
 +
  static int quit_cmd(void)
  {
        string_list_clear(&del_list, 0);
@@@ -788,9 -626,6 +788,9 @@@ static int help_cmd(void
        clean_print_color(CLEAN_COLOR_HELP);
        printf_ln(_(
                    "clean               - start cleaning\n"
 +                  "filter by pattern   - exclude items from deletion\n"
 +                  "select by numbers   - select items to be deleted by numbers\n"
 +                  "ask each            - confirm each deletion (like \"rm -i\")\n"
                    "quit                - stop cleaning\n"
                    "help                - this screen\n"
                    "?                   - help for prompt selection"
@@@ -806,9 -641,6 +806,9 @@@ static void interactive_main_loop(void
                struct menu_stuff menu_stuff;
                struct menu_item menus[] = {
                        {'c', "clean",                  0, clean_cmd},
 +                      {'f', "filter by pattern",      0, filter_by_patterns_cmd},
 +                      {'s', "select by numbers",      0, select_by_numbers_cmd},
 +                      {'a', "ask each",               0, ask_each_cmd},
                        {'q', "quit",                   0, quit_cmd},
                        {'h', "help",                   0, help_cmd},
                };
@@@ -864,23 -696,24 +864,23 @@@ int cmd_clean(int argc, const char **ar
        int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
        struct strbuf abs_path = STRBUF_INIT;
        struct dir_struct dir;
 -      static const char **pathspec;
 +      struct pathspec pathspec;
        struct strbuf buf = STRBUF_INIT;
        struct string_list exclude_list = STRING_LIST_INIT_NODUP;
        struct exclude_list *el;
        struct string_list_item *item;
        const char *qname;
 -      char *seen = NULL;
        struct option options[] = {
                OPT__QUIET(&quiet, N_("do not print names of files removed")),
                OPT__DRY_RUN(&dry_run, N_("dry run")),
                OPT__FORCE(&force, N_("force")),
                OPT_BOOL('i', "interactive", &interactive, N_("interactive cleaning")),
 -              OPT_BOOLEAN('d', NULL, &remove_directories,
 +              OPT_BOOL('d', NULL, &remove_directories,
                                N_("remove whole directories")),
                { OPTION_CALLBACK, 'e', "exclude", &exclude_list, N_("pattern"),
                  N_("add <pattern> to ignore rules"), PARSE_OPT_NONEG, exclude_cb },
 -              OPT_BOOLEAN('x', NULL, &ignored, N_("remove ignored files, too")),
 -              OPT_BOOLEAN('X', NULL, &ignored_only,
 +              OPT_BOOL('x', NULL, &ignored, N_("remove ignored files, too")),
 +              OPT_BOOL('X', NULL, &ignored_only,
                                N_("remove only ignored files")),
                OPT_END()
        };
  
        if (!interactive && !dry_run && !force) {
                if (config_set)
 -                      die(_("clean.requireForce set to true and neither -i, -n nor -f given; "
 +                      die(_("clean.requireForce set to true and neither -i, -n, nor -f given; "
                                  "refusing to clean"));
                else
 -                      die(_("clean.requireForce defaults to true and neither -i, -n nor -f given; "
 -                                "refusing to clean"));
 +                      die(_("clean.requireForce defaults to true and neither -i, -n, nor -f given;"
 +                                " refusing to clean"));
        }
  
        if (force > 1)
        for (i = 0; i < exclude_list.nr; i++)
                add_exclude(exclude_list.items[i].string, "", 0, el, -(i+1));
  
 -      pathspec = get_pathspec(prefix, argv);
 -
 -      fill_directory(&dir, pathspec);
 +      parse_pathspec(&pathspec, 0,
 +                     PATHSPEC_PREFER_CWD,
 +                     prefix, argv);
  
 -      if (pathspec)
 -              seen = xmalloc(argc > 0 ? argc : 1);
 +      fill_directory(&dir, &pathspec);
  
        for (i = 0; i < dir.nr; i++) {
                struct dir_entry *ent = dir.entries[i];
 -              int len, pos;
                int matches = 0;
 -              struct cache_entry *ce;
                struct stat st;
                const char *rel;
  
 -              /*
 -               * Remove the '/' at the end that directory
 -               * walking adds for directory entries.
 -               */
 -              len = ent->len;
 -              if (len && ent->name[len-1] == '/')
 -                      len--;
 -              pos = cache_name_pos(ent->name, len);
 -              if (0 <= pos)
 -                      continue;       /* exact match */
 -              pos = -pos - 1;
 -              if (pos < active_nr) {
 -                      ce = active_cache[pos];
 -                      if (ce_namelen(ce) == len &&
 -                          !memcmp(ce->name, ent->name, len))
 -                              continue; /* Yup, this one exists unmerged */
 -              }
 +              if (!cache_name_is_other(ent->name, ent->len))
 +                      continue;
  
                if (lstat(ent->name, &st))
                        die_errno("Cannot lstat '%s'", ent->name);
  
 -              if (pathspec) {
 -                      memset(seen, 0, argc > 0 ? argc : 1);
 -                      matches = match_pathspec(pathspec, ent->name, len,
 -                                               0, seen);
 -              }
 +              if (pathspec.nr)
 +                      matches = dir_path_match(ent, &pathspec, 0, NULL);
  
 -              if (S_ISDIR(st.st_mode)) {
 -                      if (remove_directories || (matches == MATCHED_EXACTLY)) {
 -                              rel = relative_path(ent->name, prefix, &buf);
 -                              string_list_append(&del_list, rel);
 -                      }
 -              } else {
 -                      if (pathspec && !matches)
 -                              continue;
 -                      rel = relative_path(ent->name, prefix, &buf);
 -                      string_list_append(&del_list, rel);
 -              }
 +              if (pathspec.nr && !matches)
 +                      continue;
 +
 +              if (S_ISDIR(st.st_mode) && !remove_directories &&
 +                  matches != MATCHED_EXACTLY)
 +                      continue;
 +
 +              rel = relative_path(ent->name, prefix, &buf);
 +              string_list_append(&del_list, rel);
        }
  
        if (interactive && del_list.nr > 0)
                }
                strbuf_reset(&abs_path);
        }
 -      free(seen);
  
        strbuf_release(&abs_path);
        strbuf_release(&buf);