1
+#include "builtin.h"
2
+#include "gettext.h"
3
+#include "parse-options.h"
4
+#include "url.h"
5
+#include "urlmatch.h"
6
+
7
+static const char * const builtin_url_parse_usage[] = {
8
+ N_("git url-parse [-c <component>] [--] <url>..."),
9
+ NULL
10
+};
11
+
12
+static char *component_arg;
13
+
14
+static struct option builtin_url_parse_options[] = {
15
+ OPT_STRING('c', "component", &component_arg, N_("component"),
16
+ N_("which URL component to extract")),
17
+ OPT_END(),
18
+};
19
+
20
+enum url_component {
21
+ URL_NONE = 0,
22
+ URL_SCHEME,
23
+ URL_USER,
24
+ URL_PASSWORD,
25
+ URL_HOST,
26
+ URL_PORT,
27
+ URL_PATH,
28
+};
29
+
30
+static void parse_or_die(const char *url, struct url_info *info)
31
+{
32
+ if (url_is_local_not_ssh(url)) {
33
+ if (*url == '/')
34
+ die("'%s' is not a URL; if you meant a local "
35
+ "repository, use 'file://%s'", url, url);
36
+ if (has_dos_drive_prefix(url))
37
+ die("'%s' is not a URL; if you meant a local "
38
+ "repository, use 'file:///%s'", url, url);
39
+ die("'%s' is not a URL; if you meant a local repository, "
40
+ "use a 'file://' URL with an absolute path", url);
41
+ }
42
+ if (!url_parse(url, info))
43
+ die("invalid git URL '%s': %s", url, info->err);
44
+}
45
+
46
+static enum url_component get_component_or_die(const char *arg)
47
+{
48
+ if (!strcmp("path", arg))
49
+ return URL_PATH;
50
+ if (!strcmp("host", arg))
51
+ return URL_HOST;
52
+ if (!strcmp("scheme", arg))
53
+ return URL_SCHEME;
54
+ if (!strcmp("user", arg))
55
+ return URL_USER;
56
+ if (!strcmp("password", arg))
57
+ return URL_PASSWORD;
58
+ if (!strcmp("port", arg))
59
+ return URL_PORT;
60
+ die("invalid git URL component '%s'", arg);
61
+}
62
+
63
+static char *extract_component(enum url_component component,
64
+ struct url_info *info)
65
+{
66
+ size_t offset, length;
67
+
68
+ switch (component) {
69
+ case URL_SCHEME:
70
+ offset = 0;
71
+ length = info->scheme_len;
72
+ break;
73
+ case URL_USER:
74
+ offset = info->user_off;
75
+ length = info->user_len;
76
+ break;
77
+ case URL_PASSWORD:
78
+ offset = info->passwd_off;
79
+ length = info->passwd_len;
80
+ break;
81
+ case URL_HOST:
82
+ offset = info->host_off;
83
+ length = info->host_len;
84
+ break;
85
+ case URL_PORT:
86
+ offset = info->port_off;
87
+ length = info->port_len;
88
+ break;
89
+ case URL_PATH:
90
+ offset = info->path_off;
91
+ length = info->path_len;
92
+ break;
93
+ case URL_NONE:
94
+ return NULL;
95
+ }
96
+
97
+ return xstrndup(info->url + offset, length);
98
+}
99
+
100
+int cmd_url_parse(int argc,
101
+ const char **argv,
102
+ const char *prefix,
103
+ struct repository *repo UNUSED)
104
+{
105
+ struct url_info info;
106
+ enum url_component selected = URL_NONE;
107
+ char *extracted;
108
+ int i;
109
+
110
+ argc = parse_options(argc, argv, prefix, builtin_url_parse_options,
111
+ builtin_url_parse_usage, 0);
112
+
113
+ if (argc == 0)
114
+ usage_with_options(builtin_url_parse_usage,
115
+ builtin_url_parse_options);
116
+
117
+ if (component_arg)
118
+ selected = get_component_or_die(component_arg);
119
+
120
+ for (i = 0; i < argc; i++) {
121
+ parse_or_die(argv[i], &info);
122
+
123
+ if (selected != URL_NONE) {
124
+ extracted = extract_component(selected, &info);
125
+ if (extracted) {
126
+ puts(extracted);
127
+ free(extracted);
128
+ }
129
+ }
130
+
131
+ free(info.url);
132
+ }
133
+
134
+ return 0;
135
+}