result = (char *)calloc(1, len);
result = typecallocn(char, len);
PUBLIC char * HTParse ARGS3(	CONST char *,	aName,	CONST char *,	relatedName,	int,		wanted){    char * result = NULL;    char * return_value = NULL;    int len;    char * name = NULL;    char * rel = NULL;    char * p;    char * acc_method;    struct struct_parts given, related;    CTRACE(tfp, "HTParse: aName:%s   relatedName:%s\n", aName, relatedName);    if (wanted & (PARSE_STRICTPATH | PARSE_QUERY)) { /* if detail wanted... */	if ((wanted & (PARSE_STRICTPATH | PARSE_QUERY))	    == (PARSE_STRICTPATH | PARSE_QUERY)) /* if strictpath AND query */	    wanted |= PARSE_PATH; /* then treat as if PARSE_PATH wanted */	if (wanted & PARSE_PATH) /* if PARSE_PATH wanted */	    wanted &= ~(PARSE_STRICTPATH | PARSE_QUERY); /* ignore details */    }    /*    **	Allocate the output string.    */    len = strlen(aName) + strlen(relatedName) + 10;    result = (char *)calloc(1, len);	/* Lots of space: more than enough */    if (result == NULL) {	outofmem(__FILE__, "HTParse");    }    /*    **	Make working copies of the input strings to cut up.    */    StrAllocCopy(name, aName);    StrAllocCopy(rel, relatedName);    /*    **	Cut up the strings into URL fields.    */    scan(name, &given);    scan(rel,  &related);    /*    **	Handle the scheme (access) field.    */    if (given.access && given.host && !given.relative && !given.absolute) {	if (!strcmp(given.access, "http") ||	    !strcmp(given.access, "https") ||	    !strcmp(given.access, "ftp"))	    /*	    **	Assume root.	    */	    given.absolute = "";    }    acc_method = given.access ? given.access : related.access;    if (wanted & PARSE_ACCESS) {	if (acc_method) {	    strcat(result, acc_method);	    if (wanted & PARSE_PUNCTUATION)		strcat(result, ":");	}    }    /*    **	If different schemes, inherit nothing.    **    **	We'll try complying with RFC 1808 and    **	the Fielding draft, and inherit nothing    **	if both schemes are given, rather than    **	only when they differ, except for    **	file URLs - FM    **    **	After trying it for a while, it's still    **	premature, IHMO, to go along with it, so    **	this is back to inheriting for identical    **	schemes whether or not they are "file".    **	If you want to try it again yourself,    **	uncomment the strcasecomp() below. - FM    */    if ((given.access && related.access) &&	(/* strcasecomp(given.access, "file") || */	 strcmp(given.access, related.access))) {	related.host = NULL;	related.absolute = NULL;	related.relative = NULL;	related.anchor = NULL;    }    /*    **	Handle the host field.    */    if (wanted & PARSE_HOST)	if (given.host || related.host) {	    char *tail = result + strlen(result);	    if (wanted & PARSE_PUNCTUATION)		strcat(result, "//");	    strcat(result, given.host ? given.host : related.host);#define CLEAN_URLS#ifdef CLEAN_URLS	    /*	    **	Ignore default port numbers, and trailing dots on FQDNs,	    **	which will only cause identical addresses to look different.	    */	    {		char *p2, *h;		if ((p2 = strchr(result, '@')) != NULL)		   tail = (p2 + 1);		p2 = strchr(tail, ':');		if (p2 != NULL && !isdigit((unsigned char)p2[1]))		    /*		    **	Colon not followed by a port number.		    */		    *p2 = '\0';		if (p2 != NULL && *p2 != '\0' && acc_method != NULL) {		    /*		    **	Port specified.		    */		    if ((!strcmp(acc_method, "http"	 ) && !strcmp(p2, ":80" )) ||			(!strcmp(acc_method, "https"	 ) && !strcmp(p2, ":443")) ||			(!strcmp(acc_method, "gopher"	 ) && !strcmp(p2, ":70" )) ||			(!strcmp(acc_method, "ftp"	 ) && !strcmp(p2, ":21" )) ||			(!strcmp(acc_method, "wais"	 ) && !strcmp(p2, ":210")) ||			(!strcmp(acc_method, "nntp"	 ) && !strcmp(p2, ":119")) ||			(!strcmp(acc_method, "news"	 ) && !strcmp(p2, ":119")) ||			(!strcmp(acc_method, "newspost"  ) && !strcmp(p2, ":119")) ||			(!strcmp(acc_method, "newsreply" ) && !strcmp(p2, ":119")) ||			(!strcmp(acc_method, "snews"	 ) && !strcmp(p2, ":563")) ||			(!strcmp(acc_method, "snewspost" ) && !strcmp(p2, ":563")) ||			(!strcmp(acc_method, "snewsreply") && !strcmp(p2, ":563")) ||			(!strcmp(acc_method, "finger"	 ) && !strcmp(p2, ":79" )) ||			(!strcmp(acc_method, "telnet"	 ) && !strcmp(p2, ":23" )) ||			(!strcmp(acc_method, "tn3270"	 ) && !strcmp(p2, ":23" )) ||			(!strcmp(acc_method, "rlogin"	 ) && !strcmp(p2, ":513")) ||			(!strcmp(acc_method, "cso"	 ) && !strcmp(p2, ":105")))		    *p2 = '\0'; /* It is the default: ignore it */		}		if (p2 == NULL) {		    int len2 = strlen(tail);		    if (len2 > 0) {			h = tail + len2 - 1;	/* last char of hostname */			if (*h == '.')			    *h = '\0';		/* chop final . */		    }		} else {		    h = p2;		    h--;		/* End of hostname */		    if (*h == '.') {			/*			**  Slide p2 over h.			*/			while (*p2 != '\0')			    *h++ = *p2++;			*h = '\0';	/* terminate */		    }		}	    }#endif /* CLEAN_URLS */	}    /*    **	If different hosts, inherit no path.    */    if (given.host && related.host)	if (strcmp(given.host, related.host) != 0) {	    related.absolute = NULL;	    related.relative = NULL;	    related.anchor = NULL;	}    /*    **	Handle the path.    */    if (wanted & (PARSE_PATH | PARSE_STRICTPATH | PARSE_QUERY)) {	char *tail = NULL;	int want_detail = (wanted & (PARSE_STRICTPATH | PARSE_QUERY));	if (want_detail)	    tail = result + strlen(result);	if (acc_method && !given.absolute && given.relative) {	    if (!strcasecomp(acc_method, "nntp") ||		!strcasecomp(acc_method, "snews") ||		(!strcasecomp(acc_method, "news") &&		 !strncasecomp(result, "news://", 7))) {		/*		 *  Treat all given nntp or snews paths,		 *  or given paths for news URLs with a host,		 *  as absolute.		 */		given.absolute = given.relative;		given.relative = NULL;	    }	}	if (given.absolute) {			/* All is given */	    if (wanted & PARSE_PUNCTUATION)		strcat(result, "/");	    strcat(result, given.absolute);	    CTRACE(tfp, "1\n");	} else if (related.absolute) {		/* Adopt path not name */	    strcat(result, "/");	    strcat(result, related.absolute);	    if (given.relative) {		p = strchr(result, '?');	/* Search part? */		if (p == NULL)		    p = (result + strlen(result) - 1);		for (; *p != '/'; p--)		    ;				/* last / */		p[1] = '\0';			/* Remove filename */		strcat(result, given.relative); /* Add given one */		HTSimplify (result);	    }	    CTRACE(tfp, "2\n");	} else if (given.relative) {	    strcat(result, given.relative);		/* what we've got */	    CTRACE(tfp, "3\n");	} else if (related.relative) {	    strcat(result, related.relative);	    CTRACE(tfp, "4\n");	} else {  /* No inheritance */	    if (strncasecomp(aName, "lynxcgi:", 8) &&		strncasecomp(aName, "lynxexec:", 9) &&		strncasecomp(aName, "lynxprog:", 9)) {		strcat(result, "/");	    }	    if (!strcmp(result, "news:/"))		result[5] = '*';	    CTRACE(tfp, "5\n");	}	if (want_detail) {	    p = strchr(tail, '?');	/* Search part? */	    if (p) {		if (PARSE_STRICTPATH) {		    *p = '\0';		} else {		    if (!(wanted & PARSE_PUNCTUATION))			p++;		    do {			*tail++ = *p;		    } while (*p++);		}	    } else {		if (wanted & PARSE_QUERY)		    *tail = '\0';	    }	}    }    /*    **	Handle the fragment (anchor).    */    if (wanted & PARSE_ANCHOR)	if ((given.anchor && *given.anchor) ||	    (!given.anchor && related.anchor)) {	    if (wanted & PARSE_PUNCTUATION)		strcat(result, "#");	    strcat(result, (given.anchor) ?			     given.anchor : related.anchor);	}    CTRACE(tfp, "HTParse:      result:%s\n", result);    FREE(rel);    FREE(name);    StrAllocCopy(return_value, result);    FREE(result);    return return_value;		/* exactly the right length */}