Raw
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 }