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
+
9
+struct module_list {
10
+ const struct cache_entry **entries;
11
+ int alloc, nr;
12
+};
13
+#define MODULE_LIST_INIT { NULL, 0, 0 }
14
+
15
+static 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
+
66
+static 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
+
106
+struct cmd_struct {
107
+ const char *cmd;
108
+ int (*fn)(int, const char **, const char *);
109
+};
110
+
111
+static struct cmd_struct commands[] = {
112
+ {"list", module_list},
113
+};
114
+
115
+int 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
+}