Exemplo n.º 1
0
void CLinks::OnLinkAdd() 
{
    UpdateData();
    
    // Get the edit text
    if (!m_linkType.IsEmpty() && m_linkDestination.GetWindowTextLength()) {
        CString LinkCaption;
	m_linkDestination.GetWindowText(LinkCaption);

	// Get the base address (if any)
        CString base;
        m_linkDestination.GetLBText(0, base);
        char * link = HTParse(LinkCaption, base.IsEmpty() ? "" : base, PARSE_ALL);
        link = HTSimplify(&link);
        LinkCaption = link;
        m_linkDestination.SetWindowText(LinkCaption);
        HT_FREE(link);


	// Update the combo box
	if (m_linkDestination.FindStringExact(-1, LinkCaption) == CB_ERR) {
	    m_linkDestination.InsertString(0, LinkCaption);
	    int length = m_linkDestination.GetCount();
	    if (length >= MAX_LIST_LENGTH) {
		int cnt;
		for (cnt=MAX_LIST_LENGTH; cnt < length; cnt++)
		    m_linkDestination.DeleteString(cnt);
	    }
	}

	// Write into INI file
	CWinComApp * pApp = (CWinComApp *) AfxGetApp();
	ASSERT(pApp != NULL); 
	pApp->AddLinkToIniFile(LinkCaption);

	// Update the list control with three columns
        CListCtrl &ListCtrl = m_pLinkList->GetListCtrl();

	// Insert item
	LV_ITEM lvi;
	lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
	lvi.iItem = 0;
	lvi.iSubItem = 0;
	lvi.pszText = (char *) LPCTSTR(m_linkType);
	lvi.iImage = 0;
	lvi.stateMask = LVIS_STATEIMAGEMASK;
	lvi.state = INDEXTOSTATEIMAGEMASK(1);
	int iItem = ListCtrl.InsertItem(&lvi);
	ASSERT(iItem != -1);

	// Set item text for additional columns
	ListCtrl.SetItemText(iItem,1, m_direction==0 ? _T("forward") : _T("reverse"));
	ListCtrl.SetItemText(iItem,2, (char *) LPCTSTR(LinkCaption));

	// Update changes 
	m_pLinkList->UpdateWindow();    
    }
}
Exemplo n.º 2
0
/*
**	Existing entries are replaced with new ones
*/
PRIVATE BOOL add_object (HTList * list, const char * access, const char * url,
			 BOOL regex, int regex_flags)
{
    HTProxy *me;
    if (!list || !access || !url || !*url)
	return NO;
    if ((me = (HTProxy *) HT_CALLOC(1, sizeof(HTProxy))) == NULL)
	HT_OUTOFMEM("add_object");
    StrAllocCopy(me->access, access);		     	    /* Access method */

#ifdef HT_POSIX_REGEX
    /* 
    **  If we support regular expressions then compile one up for
    **  this regular expression. Otherwise use is as a normal
    **  access scheme.
    */
    if (regex) {
	me->regex = get_regex_t(access,
				regex_flags < 0 ?
				W3C_DEFAULT_REGEX_FLAGS : regex_flags);
    } else
#endif
    {
	char *ptr = me->access;
	while ((*ptr = TOLOWER(*ptr))) ptr++;
    }

    me->url = HTParse(url, "", PARSE_ACCESS+PARSE_HOST+PARSE_PUNCTUATION);
    if (*(me->url+strlen(me->url)-1) != '/')
	StrAllocCat(me->url, "/");
    me->url = HTSimplify(&me->url);

    /* See if we already have this one */
    {
	HTList *cur = list;
	HTProxy *pres;
	while ((pres = (HTProxy *) HTList_nextObject(cur)) != NULL) {
	    if (!strcmp(pres->access, me->access))
		break;				       /* We already have it */
	}
	if (pres) {
	    HTTRACE(PROT_TRACE, "HTProxy..... replacing for `%s\' access %s\n" _ 
			me->url _ me->access);
	    HT_FREE(pres->access);
	    HT_FREE(pres->url);
#ifdef HT_POSIX_REGEX
	    if (pres->regex) regfree(pres->regex);
#endif
	    HTList_removeObject(list, (void *) pres);
	    HT_FREE(pres);
	}
	HTTRACE(PROT_TRACE, "HTProxy..... adding for `%s\' access %s\n" _ 
		    me->url _ me->access);
	HTList_addObject(list, (void *) me);
    }
    return YES;
}
Exemplo n.º 3
0
/*	Create new or find old named anchor
**	-----------------------------------
**
**	Me one is for a reference which is found in a document, and might
**	not be already loaded.
**	Note: You are not guaranteed a new anchor -- you might get an old one,
**	like with fonts.
*/
PUBLIC HTAnchor * HTAnchor_findAddress (const char * address)
{
    char *tag = HTParse (address, "", PARSE_VIEW);	        /* Any tags? */
    
    /* If the address represents a sub-anchor, we recursively load its parent,
       then we create a child anchor within that document. */
    if (*tag) {
	char *addr = HTParse(address, "", PARSE_ACCESS | PARSE_HOST |
			     PARSE_PATH | PARSE_PUNCTUATION);
	HTParentAnchor * parent = (HTParentAnchor*) HTAnchor_findAddress(addr);
	HTChildAnchor * child = HTAnchor_findChild(parent, tag);
	HT_FREE(addr);
	HT_FREE(tag);
	return (HTAnchor *) child;
    } else {		       	     /* Else check whether we have this node */
	int hash;
	const char *p;
	HTList * adults;
	HTList *grownups;
	HTParentAnchor * foundAnchor;
	char *newaddr = NULL;
	StrAllocCopy(newaddr, address);		         /* Get our own copy */
	HT_FREE(tag);
	newaddr = HTSimplify(&newaddr);

	/* Select list from hash table */
	for(p=newaddr, hash=0; *p; p++)
	    hash = (int) ((hash * 3 + (*(unsigned char*)p)) % PARENT_HASH_SIZE);
	if (!adult_table) {
	    if ((adult_table = (HTList* *) HT_CALLOC(PARENT_HASH_SIZE, sizeof(HTList*))) == NULL)
	        HT_OUTOFMEM("HTAnchor_findAddress");
	}
	if (!adult_table[hash]) adult_table[hash] = HTList_new();
	adults = adult_table[hash];

	/* Search list for anchor */
	grownups = adults;
	while ((foundAnchor = (HTParentAnchor *) HTList_nextObject(grownups))){
	    if (!strcmp(foundAnchor->address, newaddr)) {
		HTTRACE(ANCH_TRACE, "Find Parent. %p with address `%s' already exists.\n" _ 
			    (void*) foundAnchor _ newaddr);
		HT_FREE(newaddr);		       /* We already have it */
		return (HTAnchor *) foundAnchor;
	    }
	}
	
	/* Node not found : create new anchor. */
	foundAnchor = HTParentAnchor_new();
	foundAnchor->address = newaddr;			/* Remember our copy */
	HTList_addObject (adults, foundAnchor);
	HTTRACE(ANCH_TRACE, "Find Parent. %p with hash %d and address `%s' created\n" _ (void*)foundAnchor _ hash _ newaddr);
	return (HTAnchor *) foundAnchor;
    }
}
Exemplo n.º 4
0
void CLocation::OnBrowse()
{
    CWinComApp * pApp = (CWinComApp *) AfxGetApp();
    ASSERT(pApp != NULL); 

    CFileDialog fd(TRUE);
    fd.m_ofn.lpstrInitialDir = pApp->GetIniCWD();
    UpdateData();
    if (fd.DoModal() == IDOK) {
	
	// Make the source an absolute URI
	CString path = fd.GetPathName();
	char * fileaddr = HTLocalToWWW(path, NULL);
	if (fileaddr) {
	    m_source = fileaddr;
	    m_sourceList.SetWindowText(fileaddr);
	    
	    // Set the initial dir for next time
	    int idx = path.ReverseFind('\\');
	    if (idx != -1) path.GetBufferSetLength(idx+1);
	    pApp->SetIniCWD(path);

	    HT_FREE(fileaddr);
	}

	/* Update the destination */
	CString file = fd.GetFileName();
	if (!file.IsEmpty()) {
            CString base = "";
	    char * escaped = HTEscape(file, URL_XALPHAS);
	    char * destination = escaped;
	    int length = m_destinationList.GetCount();
	    if (length > 0) {
		m_destinationList.GetLBText(0, base);
		if (!base.IsEmpty()) {
		    destination = HTParse(escaped, base, PARSE_ALL);
		    HT_FREE(escaped);
		}
	    }
	    destination = HTSimplify(&destination);
	    m_destination = destination;
	    m_destinationList.SetWindowText(m_destination);
	    HT_FREE(destination);
	}

	// If change in source then update the entity and link info
        ASSERT(GetParentFrame()->GetActiveView()->IsKindOf(RUNTIME_CLASS(CTabsView)));
	CTabsView * view = (CTabsView *) GetParentFrame()->GetActiveView();
	view->GetDocument()->m_EntityInfo.Clear();
        view->GetDocument()->m_Links.Clear();

        UpdateData();
    }
}
Exemplo n.º 5
0
/*		Make Relative Name
**		------------------
**
** This function creates and returns a string which gives an expression of
** one address as related to another. Where there is no relation, an absolute
** address is retured.
**
**  On entry,
**	Both names must be absolute, fully qualified names of nodes
**	(no fragment bits)
**
**  On exit,
**	The return result points to a newly allocated name which, if
**	parsed by HTParse relative to relatedName, will yield aName.
**	The caller is responsible for freeing the resulting name later.
**
*/
PUBLIC char * HTRelative (const char * aName, const char * relatedName)
{
    char * result = 0;
    const char *p = aName;
    const char *q = relatedName;
    const char * after_access = NULL;
    const char * path = 0;
    const char * last_slash = 0;
    int slashes = 0;
    
    for(;*p; p++, q++) {	/* Find extent of match */
    	if (*p!=*q) break;
	if (*p==':') if (!after_access) after_access = p+1;
	if (*p=='/') {
	    last_slash = p;
	    slashes++;
	    if (slashes==3) path=p;
	}
    }
    
    /* q, p point to the first non-matching character or zero */
    
    if (!after_access) {			/* Different access */
        StrAllocCopy(result, aName);
    } else if (slashes<3){			/* Different nodes */
    	StrAllocCopy(result, after_access);
    } else {					/* Some path in common */
        int levels= 0;
        for(; *q && *q!='#' && *q!=';' && *q!='?'; q++) if (*q=='/') levels++;
	if ((result = (char  *) HT_MALLOC(3*levels + strlen(last_slash) + 4)) == NULL)
	    HT_OUTOFMEM("HTRelative");
	*result = '\0';
	if (!levels) strcat(result, "./");
	for(;levels; levels--)strcat(result, "../");
	strcat(result, last_slash+1);
	if (!*result) strcat(result, "./");
    }
    HTTRACE(URI_TRACE, "HTRelative.. `%s' expressed relative to  `%s' is `%s'\n" _ 
		aName _ relatedName _ result);
#if 0
    {
	char * absstr = HTParse(result, relatedName, PARSE_ALL);
	HTSimplify(&absstr);
	HTTRACE(URI_TRACE, "HTRelative.. `%s' made absolute based on `%s' is `%s'\n" _
		result _ relatedName _ absstr);
	if (strcmp(absstr, aName) != 0) HTTRACE(URI_TRACE, "THEY DIFFER!!!\n");
	HT_FREE(absstr);
    }
#endif
    return result;
}
Exemplo n.º 6
0
int HTSimplify_tcl(ClientData clientData, Tcl_Interp *interp, 
		   int argc, char **argv) {
  if (argc == 2) {
    char *str      = argv[1];
    if (str) {
      char *result = HTSimplify(&str);
      Tcl_AppendResult(interp, result, NULL);
      return TCL_OK;
    }
    Tcl_AppendResult(interp, bad_vars, NULL);
    return TCL_ERROR;
  }
  else {
    Tcl_AppendResult(interp, err_string, argv[0], "string", NULL);
    return TCL_ERROR;
  }
}
Exemplo n.º 7
0
void CDelete::OnOK() 
{
    CWinComApp * pApp = (CWinComApp *) AfxGetApp();
    ASSERT(pApp != NULL); 

    // Check address to delete
    if (m_deleteList.GetWindowTextLength()) {
	m_deleteList.GetWindowText(m_address);
	if (m_address.IsEmpty()) return;
	
	// Get the base address (if any)
	CString base;
	m_deleteList.GetLBText(0, base);
	char * address = HTParse(m_address, base.IsEmpty() ? "" : base, PARSE_ALL);
	address = HTSimplify(&address);
	m_address = address;
	m_deleteList.SetWindowText(m_address);
	HT_FREE(address);
	HTAnchor * anchor = HTAnchor_findAddress(m_address);
	
	// Update the address combo box
	if (m_deleteList.FindStringExact(-1, m_address) == CB_ERR) {
	    m_deleteList.InsertString(0, m_address);
	    int srcLength = m_deleteList.GetCount();
	    if (srcLength >= MAX_LIST_LENGTH) {
		int cnt;
		for (cnt=MAX_LIST_LENGTH; cnt < srcLength; cnt++)
		    m_deleteList.DeleteString(cnt);
	    }
	    
	    // Write into INI file
	    pApp->AddDeleteAddressToIniFile(m_address);
	}
	
	
	// Start the request
	CRequest * request = new CRequest(m_pDoc);
	request->DeleteDocument(anchor, HT_NO_MATCH);
    }
    CDialog::OnOK();
}
Exemplo n.º 8
0
/*      Scan a filename for its consituents.                    scan()
   **   ------------------------------------
   **
   ** On entry,
   **   name    points to a document name which may be incomplete.
   ** On exit,
   **      absolute or relative may be nonzero (but not both).
   **   host, anchor and access may be nonzero if they were specified.
   **   Any which are nonzero point to zero terminated strings.
 */
PRIVATE void    scan
ARGS2(char *, name, struct struct_parts *, parts)
{
    char           *after_access;
    char           *p;
    /* int length = strlen (name); */

    parts->access = NULL;
    parts->host = NULL;
    parts->absolute = NULL;
    parts->relative = NULL;
    parts->anchor = NULL;

    /* 
     **  Scan left-to-right for a scheme (access).
     */
    after_access = name;
    for (p = name; *p; p++) {
        if (*p == ':') {
            *p = '\0';
            parts->access = name;       /* Access name has been specified */
            after_access = (p + 1);
            break;
        }
        if (*p == '/' || *p == '#' || *p == ';' || *p == '?')
            break;
    }

#ifdef NOTDEFINED
    for (p = (name + length - 1); p >= name; p--) {
#endif                          /* NOTDEFINED */
        /* 
         **  Scan left-to-right for a fragment (anchor).
         */
        for (p = after_access; *p; p++) {
            if (*p == '#') {
                parts->anchor = (p + 1);
                *p = '\0';      /* terminate the rest */
            }
        }

        /* 
         **  Scan left-to-right for a host or absolute path.
         */
        p = after_access;
        if (*p == '/') {
            if (p[1] == '/') {
                parts->host = (p + 2);  /* host has been specified */
                *p = '\0';      /* Terminate access */
                p = strchr(parts->host, '/');   /* look for end of host name if any */
                if (p != NULL) {
                    *p = '\0';  /* Terminate host */
                    parts->absolute = (p + 1);  /* Root has been found */
                }
            } else {
                parts->absolute = (p + 1);      /* Root found but no host */
            }
        } else {
            parts->relative = (*after_access) ? after_access : NULL;    /* NULL for
                                                                         * "" */
        }

        /* 
         **  Check schemes that commonly have unescaped hashes.
         */
        if (parts->access && parts->anchor) {
            if ((!parts->host && strcasecomp(parts->access, "lynxcgi")) ||
                !strcasecomp(parts->access, "nntp") ||
                !strcasecomp(parts->access, "snews") ||
                !strcasecomp(parts->access, "news") ||
                !strcasecomp(parts->access, "data")) {
                /* 
                 *  Access specified but no host and not a lynxcgi URL, so the
                 *  anchor may not really be one, e.g., news:j462#[email protected],
                 *  or it's an nntp or snews URL, or news URL with a host.
                 *  Restore the '#' in the address.
                 */
                *(parts->anchor - 1) = '#';
                parts->anchor = NULL;
            }
        }
#ifdef NOT_DEFINED              /* search is just treated as part of path */
        {
            char           *p = (relative ? relative : absolute);
            if (p != NULL) {
                char           *q = strchr(p, '?');     /* Any search string? */
                if (q != NULL) {
                    *q = '\0';  /* If so, chop that off. */
                    parts->search = (q + 1);
                }
            }
        }
#endif                          /* NOT_DEFINED */
    }                           /* scan */


/*      Parse a Name relative to another name.                  HTParse()
   **   --------------------------------------
   **
   **   This returns those parts of a name which are given (and requested)
   **   substituting bits from the related name where necessary.
   **
   ** On entry,
   **   aName           A filename given
   **      relatedName     A name relative to which aName is to be parsed
   **      wanted          A mask for the bits which are wanted.
   **
   ** On exit,
   **   returns         A pointer to a malloc'd string which MUST BE FREED
 */
    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           *access;
        struct struct_parts given, related;

        if (TRACE)
            fprintf(stderr,
                    "HTParse: aName:%s   relatedName:%s\n", aName, relatedName);

        /* 
         **  Allocate the output string.
         */
        len = strlen(aName) + strlen(relatedName) + 10;
        result = (char *) malloc(len);  /* Lots of space: more than enough */
        if (result == NULL)
            outofmem(__FILE__, "HTParse");
        result[0] = '\0';       /* Clear string */

        /* 
         **  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 = "";
        }
        access = given.access ? given.access : related.access;
        if (wanted & PARSE_ACCESS) {
            if (access) {
                strcat(result, access);
                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 strncasecomp() 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           *p, *h;
                    p = strchr(tail, ':');
                    if (p != NULL && !isdigit((unsigned char) p[1]))
                        /* 
                         **  Colon not followed by a port number.
                         */
                        *p = '\0';
                    if (p != NULL && p != '\0' && access != NULL) {
                        /* 
                         **  Port specified.
                         */
                        if ((!strcmp(access, "http") && !strcmp(p, ":80")) ||
                            (!strcmp(access, "gopher") && !strcmp(p, ":70")) ||
                            (!strcmp(access, "ftp") && !strcmp(p, ":21")) ||
                            (!strcmp(access, "wais") && !strcmp(p, ":210")) ||
                            (!strcmp(access, "nntp") && !strcmp(p, ":119")) ||
                            (!strcmp(access, "news") && !strcmp(p, ":119")) ||
                            (!strcmp(access, "snews") && !strcmp(p, ":563")) ||
                            (!strcmp(access, "finger") && !strcmp(p, ":79")) ||
                            (!strcmp(access, "cso") && !strcmp(p, ":105")))
                            *p = '\0';  /* It is the default: ignore it */
                    }
                    if (p == NULL) {
                        int             len = strlen(tail);

                        if (len > 0) {
                            h = tail + len - 1; /* last char of hostname */
                            if (*h == '.')
                                *h = '\0';      /* chop final . */
                        }
                    } else {
                        h = p;
                        h--;    /* End of hostname */
                        if (*h == '.') {
                            /* 
                             **  Slide p over h.
                             */
                            while (*p != '\0')
                                *h++ = *p++;
                            *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) {
            if (access && !given.absolute && given.relative) {
                if (!strcasecomp(access, "nntp") ||
                    !strcasecomp(access, "snews") ||
                    (!strcasecomp(access, "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);
                if (TRACE)
                    fprintf(stderr, "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);
                }
                if (TRACE)
                    fprintf(stderr, "2\n");
            } else if (given.relative) {
                strcat(result, given.relative); /* what we've got */
                if (TRACE)
                    fprintf(stderr, "3\n");
            } else if (related.relative) {
                strcat(result, related.relative);
                if (TRACE)
                    fprintf(stderr, "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] = '*';
                if (TRACE)
                    fprintf(stderr, "5\n");
            }
        }

        /* 
         **  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);
            }
        if (TRACE)
            fprintf(stderr, "HTParse: result:%s\n", result);
        FREE(rel);
        FREE(name);

        StrAllocCopy(return_value, result);
        FREE(result);

        return return_value;    /* exactly the right length */
    }
Exemplo n.º 9
0
/*	Parse a Name relative to another name
**	-------------------------------------
**
**	This returns those parts of a name which are given (and requested)
**	substituting bits from the related name where necessary.
**
** On entry,
**	aName		A filename given
**      relatedName     A name relative to which aName is to be parsed. Give
**                      it an empty string if aName is absolute.
**      wanted          A mask for the bits which are wanted.
**
** On exit,
**	returns		A pointer to a malloc'd string which MUST BE FREED
*/
PUBLIC char * HTParse (const char *aName, const char *relatedName, int wanted)
{
    char * result = 0;
    char * return_value = 0;
    int len;
    char * name = 0;
    char * rel = 0;
    char * p;
    char * access;
    HTURI given, related;
    
    if (!aName) return NULL;
    if (!relatedName)        /* HWL 23/8/94: dont dump due to NULL */
        relatedName = "";
    
    /* Make working copies of input strings to cut up: */
    len = strlen(aName)+strlen(relatedName)+10;
    if ((result=(char *) HT_MALLOC(len)) == NULL) /* Lots of space: more than enough */
	HT_OUTOFMEM("parse space");
    StrAllocCopy(name, aName);
    StrAllocCopy(rel, relatedName);
    
    scan(name, &given);
    scan(rel,  &related); 
    result[0]=0;		/* Clear string  */
    access = given.access ? given.access : related.access;
    if (wanted & PARSE_ACCESS)
        if (access) {
	    strcat(result, access);
	    if(wanted & PARSE_PUNCTUATION) strcat(result, ":");
	}
	
    if (given.access && related.access)	/* If different, inherit nothing. */
        if (strcmp(given.access, related.access)!=0) {
	    related.host=0;
	    related.absolute=0;
	    related.relative=0;
	    related.fragment=0;
	}
	
    if (wanted & PARSE_HOST)
        if(given.host || related.host) {
	    if(wanted & PARSE_PUNCTUATION) strcat(result, "//");
	    strcat(result, given.host ? given.host : related.host);
	}
	
    if (given.host && related.host)  /* If different hosts, inherit no path. */
        if (strcmp(given.host, related.host)!=0) {
	    related.absolute=0;
	    related.relative=0;
	    related.fragment=0;
	}
	
    if (wanted & PARSE_PATH) {
        if(given.absolute) {				/* All is given */
	    if(wanted & PARSE_PUNCTUATION) strcat(result, "/");
	    strcat(result, given.absolute);
	} else if(related.absolute) {	/* Adopt path not name */
	    strcat(result, "/");
	    strcat(result, related.absolute);
	    if (given.relative) {
		p = strchr(result, '?');	/* Search part? */
		if (!p) p=result+strlen(result)-1;
		for (; *p!='/'; p--);	/* last / */
		p[1]=0;					/* Remove filename */
		strcat(result, given.relative);		/* Add given one */
#if 0
		result = HTSimplify (&result);
#endif
	    }
	} else if(given.relative) {
	    strcat(result, given.relative);		/* what we've got */
	} else if(related.relative) {
	    strcat(result, related.relative);
	} else {  /* No inheritance */
	    strcat(result, "/");
	}
    }
		
    if (wanted & PARSE_VIEW)
	if(given.fragment || related.fragment) {
	    if(given.absolute && given.fragment) {   /*Fixes for relURLs...*/
		if(wanted & PARSE_PUNCTUATION) strcat(result, "#");
		strcat(result, given.fragment); 
	    } else if (!(given.absolute) && !(given.fragment)) {
		strcat(result, "");
	    } else {
		if(wanted & PARSE_PUNCTUATION) strcat(result, "#");
		strcat(result, given.fragment ? given.fragment : related.fragment); 
	    }
	}
    HT_FREE(rel);
    HT_FREE(name);
    
    StrAllocCopy(return_value, result);
    HT_FREE(result);
    return return_value;		/* exactly the right length */
}