10db4e6f6a5c5ec38bfe2ce85c524c97aa85e561
   1#include "builtin.h"
   2#include "cache.h"
   3#include "parse-options.h"
   4#include "quote.h"
   5#include "pathspec.h"
   6#include "dir.h"
   7#include "utf8.h"
   8
   9struct module_list {
  10        const struct cache_entry **entries;
  11        int alloc, nr;
  12};
  13#define MODULE_LIST_INIT { NULL, 0, 0 }
  14
  15static int module_list_compute(int argc, const char **argv,
  16                               const char *prefix,
  17                               struct pathspec *pathspec,
  18                               struct module_list *list)
  19{
  20        int i, result = 0;
  21        char *max_prefix, *ps_matched = NULL;
  22        int max_prefix_len;
  23        parse_pathspec(pathspec, 0,
  24                       PATHSPEC_PREFER_FULL |
  25                       PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
  26                       prefix, argv);
  27
  28        /* Find common prefix for all pathspec's */
  29        max_prefix = common_prefix(pathspec);
  30        max_prefix_len = max_prefix ? strlen(max_prefix) : 0;
  31
  32        if (pathspec->nr)
  33                ps_matched = xcalloc(pathspec->nr, 1);
  34
  35        if (read_cache() < 0)
  36                die(_("index file corrupt"));
  37
  38        for (i = 0; i < active_nr; i++) {
  39                const struct cache_entry *ce = active_cache[i];
  40
  41                if (!S_ISGITLINK(ce->ce_mode) ||
  42                    !match_pathspec(pathspec, ce->name, ce_namelen(ce),
  43                                    max_prefix_len, ps_matched, 1))
  44                        continue;
  45
  46                ALLOC_GROW(list->entries, list->nr + 1, list->alloc);
  47                list->entries[list->nr++] = ce;
  48                while (i + 1 < active_nr &&
  49                       !strcmp(ce->name, active_cache[i + 1]->name))
  50                        /*
  51                         * Skip entries with the same name in different stages
  52                         * to make sure an entry is returned only once.
  53                         */
  54                        i++;
  55        }
  56        free(max_prefix);
  57
  58        if (ps_matched && report_path_error(ps_matched, pathspec, prefix))
  59                result = -1;
  60
  61        free(ps_matched);
  62
  63        return result;
  64}
  65
  66static int module_list(int argc, const char **argv, const char *prefix)
  67{
  68        int i;
  69        struct pathspec pathspec;
  70        struct module_list list = MODULE_LIST_INIT;
  71
  72        struct option module_list_options[] = {
  73                OPT_STRING(0, "prefix", &prefix,
  74                           N_("path"),
  75                           N_("alternative anchor for relative paths")),
  76                OPT_END()
  77        };
  78
  79        const char *const git_submodule_helper_usage[] = {
  80                N_("git submodule--helper list [--prefix=<path>] [<path>...]"),
  81                NULL
  82        };
  83
  84        argc = parse_options(argc, argv, prefix, module_list_options,
  85                             git_submodule_helper_usage, 0);
  86
  87        if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0) {
  88                printf("#unmatched\n");
  89                return 1;
  90        }
  91
  92        for (i = 0; i < list.nr; i++) {
  93                const struct cache_entry *ce = list.entries[i];
  94
  95                if (ce_stage(ce))
  96                        printf("%06o %s U\t", ce->ce_mode, sha1_to_hex(null_sha1));
  97                else
  98                        printf("%06o %s %d\t", ce->ce_mode, sha1_to_hex(ce->sha1), ce_stage(ce));
  99
 100                utf8_fprintf(stdout, "%s\n", ce->name);
 101        }
 102        return 0;
 103}
 104
 105
 106struct cmd_struct {
 107        const char *cmd;
 108        int (*fn)(int, const char **, const char *);
 109};
 110
 111static struct cmd_struct commands[] = {
 112        {"list", module_list},
 113};
 114
 115int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 116{
 117        int i;
 118        if (argc < 2)
 119                die(_("fatal: submodule--helper subcommand must be "
 120                      "called with a subcommand"));
 121
 122        for (i = 0; i < ARRAY_SIZE(commands); i++)
 123                if (!strcmp(argv[1], commands[i].cmd))
 124                        return commands[i].fn(argc - 1, argv + 1, prefix);
 125
 126        die(_("fatal: '%s' is not a valid submodule--helper "
 127              "subcommand"), argv[1]);
 128}