| 2931 | } |
| 2932 | |
| 2933 | char *relative_url(const char *remote_url, const char *url, |
| 2934 | const char *up_path) |
| 2935 | { |
| 2936 | int is_relative = 0; |
| 2937 | int colonsep = 0; |
| 2938 | char *out; |
| 2939 | char *remoteurl; |
| 2940 | struct strbuf sb = STRBUF_INIT; |
| 2941 | size_t len; |
| 2942 | |
| 2943 | if (!url_is_local_not_ssh(url) || is_absolute_path(url)) |
| 2944 | return xstrdup(url); |
| 2945 | |
| 2946 | len = strlen(remote_url); |
| 2947 | if (!len) |
| 2948 | BUG("invalid empty remote_url"); |
| 2949 | |
| 2950 | remoteurl = xstrdup(remote_url); |
| 2951 | if (is_dir_sep(remoteurl[len-1])) |
| 2952 | remoteurl[len-1] = '\0'; |
| 2953 | |
| 2954 | if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl)) |
| 2955 | is_relative = 0; |
| 2956 | else { |
| 2957 | is_relative = 1; |
| 2958 | /* |
| 2959 | * Prepend a './' to ensure all relative |
| 2960 | * remoteurls start with './' or '../' |
| 2961 | */ |
| 2962 | if (!starts_with_dot_slash_native(remoteurl) && |
| 2963 | !starts_with_dot_dot_slash_native(remoteurl)) { |
| 2964 | strbuf_reset(&sb); |
| 2965 | strbuf_addf(&sb, "./%s", remoteurl); |
| 2966 | free(remoteurl); |
| 2967 | remoteurl = strbuf_detach(&sb, NULL); |
| 2968 | } |
| 2969 | } |
| 2970 | /* |
| 2971 | * When the url starts with '../', remove that and the |
| 2972 | * last directory in remoteurl. |
| 2973 | */ |
| 2974 | while (*url) { |
| 2975 | if (starts_with_dot_dot_slash_native(url)) { |
| 2976 | url += 3; |
| 2977 | colonsep |= chop_last_dir(&remoteurl, is_relative); |
| 2978 | } else if (starts_with_dot_slash_native(url)) |
| 2979 | url += 2; |
| 2980 | else |
| 2981 | break; |
| 2982 | } |
| 2983 | strbuf_reset(&sb); |
| 2984 | strbuf_addf(&sb, "%s%s%s", remoteurl, colonsep ? ":" : "/", url); |
| 2985 | if (ends_with(url, "/")) |
| 2986 | strbuf_setlen(&sb, sb.len - 1); |
| 2987 | free(remoteurl); |
| 2988 | |
| 2989 | if (starts_with_dot_slash_native(sb.buf)) |
| 2990 | out = xstrdup(sb.buf + 2); |