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(); } }
/* ** 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; }
/* 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; } }
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(); } }
/* 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; }
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; } }
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(); }
/* 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 */ }
/* 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 */ }