| #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; | |
| } |