	Convert a URI to a string

	The function [[uri2str]] allocates a string on the heap and
	writes a representation of the [[uri]] in it (properly
	escaped).

<<*>>=
#include <config.h>
#include <str.h>
#include "uri.e"

#define INCR 128

static void append_esc(char **s, const char *t, int *len)
{
    int n;

    n = strlen(t);
    renewarray(*s, ((*len + 3 * n + 1 + INCR - 1)/INCR) * INCR);
    *len += URL_strcpy_escaped(*s + *len, t);
}


static void append(char **s, const char *t, int *len)
{
    int n;

    n = strlen(t);
    renewarray(*s, ((*len + n + 1 + INCR - 1)/INCR) * INCR);
    strcpy(*s + *len, t);
    *len += n;
}


EXPORT char *uri2str(const URI uri)
{
    char *s = NULL;
    int n = 0;

    switch (uri.tp) {
    case URI_URL:
	append_esc(&s, strip2str(uri.scheme), &n);
	append(&s, ":", &n);
	if (uri.host) {
	    append(&s, "//", &n);
	    if (uri.user) {
		append_esc(&s, strip2str(uri.user), &n);
		if (uri.passw) {
		    append(&s, ":", &n);
		    append_esc(&s, strip2str(uri.user), &n);
		}
		append(&s, "@", &n);
	    }
	    append_esc(&s, strip2str(uri.host), &n);
	    if (uri.port) {
		append(&s, ":", &n);
		append_esc(&s, strip2str(uri.port), &n);
	    }
	}
	append(&s, strip2str(uri.path), &n);
	if (uri.search) {
	    append(&s, "?", &n);
	    append(&s, strip2str(uri.search), &n);
	}
	if (uri.anchor) {
	    append(&s, "#", &n);
	    append(&s, strip2str(uri.anchor), &n);
	}
	break;
    case URI_URN:
	append(&s, strip2str(uri.scheme), &n);
	append(&s, ":", &n);
	append_esc(&s, strip2str(uri.path), &n);
	break;
    case URI_Rel:
	if (uri.path) {
	    append_esc(&s, strip2str(uri.path), &n);
	}
	if (uri.search) {
	    append(&s, "?", &n);
	    append(&s, strip2str(uri.search), &n);
	}
	if (uri.anchor) {
	    append(&s, "#", &n);
	    append_esc(&s, strip2str(uri.anchor), &n);
	}
	break;
    default:
	s = NULL;
    }
    return s;
}
