]> git.ipfire.org Git - thirdparty/git.git/blame - builtin/submodule--helper.c
submodule: rewrite `module_list` shell function in C
[thirdparty/git.git] / builtin / submodule--helper.c
CommitLineData
74703a1e
SB
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}