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