#line 4 "relative.c-nw"
#include <config.h>
#include <str.h>
#include "uri.e"

EXPORT void URL_expand(URI *uri, const URI base)
{
    char *s, *p, *t, *h;
    int n, a, b, c, d;

    uri->tp = base.tp;
    if (uri->scheme) return;                    /* Not relative at all! */
    uri->scheme = base.scheme;
    if (uri->host) return;                      /* Rest is not relative */
    uri->user = base.user;
    uri->passw = base.passw;
    uri->host = base.host;
    uri->port = base.port;
    h = strip2str(uri->path);
    if (uri->path == NULL) {                    /* No relative path */
        uri->path = base.path;
    } else if (h[0] != '/') {                   /* Doesn't start at root */
        s = strip2str(base.path);
        p = strrchr(s, '/');                    /* Last `/' in base */
        if (p) {
            n = p - s;                          /* Length of directory part */
            newarray(t, n + strlen(h) + 2);     /* Room for new path */
            strncpy(t, s, n);                   /* Copy directory */
            t[n] = '/';                         /* Add a slash */
            strcpy(t + n + 1, h);               /* Append the rel. path */

            n = strlen(t);

            b = 0;
            assert(t[0] == '/');
            while (t[b]) {                      /* Remove `.' directories */
                for (c = b + 1; t[c] && t[c] != '/'; c++) ;
                if (c == b + 2 && t[b+1] == '.') {
                    memmove(t + b, t + c, n - c + 1); n -= 2;
                } else
                    b = c;
            }
            b = d = 0;
            while (t[b] == '/') {               /* Remove `..' directories */
                for (c = b + 1; t[c] && t[c] != '/'; c++) ;
                if (c == b + 3 && t[b+1] == '.' && t[b + 2] == '.') {
                    for (a = b - 1; a >= d && t[a] != '/'; a--) ;
                    if (a >= d) {
                        memmove(t + a, t + c, n - c + 1); n -= c - a; b = a;
                    } else {
                        b = c; d = c;
                    }
                } else
                    b = c;
            }
#if 0
            /* Remove `.' directories */
            for (i = n - 3; i > 0; i--) {
                if (n_eq(t + i, "/./", 3)) {
                    memmove(t + i + 1, t + i + 3, n - i - 2);
                    n -= 2;
                }
            }
            /* Remove `/.' at end */
            if (n > 2 && n_eq(t + n - 2, "/.", 2)) {
                n -= 2;
                t[n] = '\0';
            }
            /* Remove `..' directories */
            for (i = n - 4; i > 0; i--) {
                if (n_eq(t + i, "/../", 4)) {
                    for (j = i - 1; j != 0 && t[j] != '/'; j--) ;
                    if (t[j] == '/') {
                        memmove(t + j + 1, t + i + 4, n - i - 3);
                        i = j + 1;
                        n -= i - j + 3;
                    }
                }
            }
            /* Remove `/..' at end */
            if (n > 3 && n_eq(t + n - 3, "/..", 3)) {
                for (j = n - 4; j != 0 && t[j] != '/'; j--) ;
                if (t[j] == '/') {
                    t[j] = '\0';
                    n = j;
                }
            }
#endif
            uri->path = str2strip(t);
            dispose(t);
        }
    }
}