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