	Expand a relative URL

<<*>>=
#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);
	}
    }
}
