char *STRTOK_R(char *pStr, const char *pDelims, char **ppSave) { if (!pStr) pStr = *ppSave; while (IsDelim(*pStr, pDelims)) pStr++; if (!*pStr) { *ppSave = pStr; return NULL; } char *pToken = pStr; while (*pStr && !IsDelim(*pStr, pDelims)) pStr++; if (*pStr) *pStr++ = 0; *ppSave = pStr; return pToken; }
ItTokenizer::Token ItTokenizer::NextToken() { const char* cur = end; while('\0' != *cur && IsDelim(delim, *cur)) cur++; start = cur; while('\0' != *cur && !IsDelim(delim, *cur)) cur++; end = cur; return Token(start, end); }
static inline Stroka GetFile(const Stroka& s) { const char* e = s.end(); const char* b = s.begin(); const char* c = e - 1; while (c != b && !IsDelim(*c)) { --c; } if (c != e && IsDelim(*c)) { ++c; } return Stroka(c, e - c); }
// expected string: "content", returned string: content ItTokenizer::Token ItTokenizer::ExpectStr(std::string& str) { const char* cur = end; while('\0' != *cur && IsDelim(delim, *cur)) cur++; const char *nstart = cur; if('\"' != *cur++) { char tokBuf[512] = { 0 }; strncpy(tokBuf, nstart, 1); common.printf("ERROR - %s: ", this->name); common.printf("expecting STRING, got '%s'\n", tokBuf); Crash(); } while('\0' != *cur) { if('\"' == *cur) { str = std::string(nstart + 1, cur - nstart - 1); start = nstart; end = cur + 1; return Token(start, end); } cur++; } char tokBuf[512] = { 0 }; strncpy(tokBuf, nstart, 512); common.printf("ERROR - %s: ", this->name); common.printf("expecting STRING, got '%s'\n", tokBuf); Crash(); // unreachable return Token(NULL, NULL); }
static inline Stroka Fix(Stroka f) { if (!f.empty() && IsDelim(f[+f - 1])) { f.pop_back(); } return f; }
ItTokenizer::Token ItTokenizer::ExpectFloat(float &val) { const char* cur = end; while('\0' != *cur && IsDelim(delim, *cur)) cur++; const char *nstart = cur; bool negative = false; float num = 0; if('-' == *cur) { negative = true; cur++; } if(!isdigit(*cur)) { char tokBuf[512] = { 0 }; strncpy(tokBuf, nstart, 1); common.printf("ERROR - %s: ", this->name); common.printf("expecting FLOAT, got '%s'\n", tokBuf); Crash(); } while(isdigit(*cur)) { num *= 10.0f; num += *cur - '0'; cur++; } if('.' == *cur) { cur++; float pow = 0.1f; while(isdigit(*cur)) { num += pow * (*cur - '0'); pow /= 10.0f; cur++; } } if(negative) num *= -1; val = num; start = nstart; end = cur; return Token(start, end); }
ItTokenizer::Token ItTokenizer::Expect(const char* name) { const char* cur = end; while('\0' != *cur && IsDelim(delim, *cur)) cur++; const char *nstart = cur, *nameCur = name; while('\0' != *nameCur) { if(*cur++ != *nameCur++) { char tokBuf[512] = { 0 }; strncpy(tokBuf, nstart, cur - nstart); common.printf("ERROR - %s: ", this->name); common.printf("expecting '%s', got '%s'\n", name, tokBuf); Crash(); } } start = nstart; end = cur; return Token(start, end); }
ItTokenizer::Token ItTokenizer::ExpectInt(int& val) { const char* cur = end; while('\0' != *cur && IsDelim(delim, *cur)) cur++; const char *nstart = cur; bool negative = false; int num = 0; int arity = 1; if('-' == *cur) { negative = true; cur++; } if(!isdigit(*cur)) { char tokBuf[512] = { 0 }; strncpy(tokBuf, nstart, 1); common.printf("ERROR - %s: ", this->name); common.printf("expecting INT, got '%s'\n", tokBuf); Crash(); } while(isdigit(*cur)) { num *= 10; num += *cur - '0'; cur++; } if(negative) num *= -1; val = num; start = nstart; end = cur; return Token(start, end); }
void op_extract() { /* Stack: |=============================|=============================| | BEFORE | AFTER | |=============================|=============================| top | Subvalue number | Substring | |-----------------------------|-----------------------------| | Value number | | |-----------------------------|-----------------------------| | Field number | | |-----------------------------|-----------------------------| | Source string | | |=============================|=============================| */ DESCRIPTOR * field_descr; /* Position descriptor */ DESCRIPTOR * value_descr; /* Position descriptor */ DESCRIPTOR * subvalue_descr; /* Position descriptor */ DESCRIPTOR * src_descr; /* Source string */ DESCRIPTOR result_descr; /* Result string */ long int field; long int value; long int subvalue; short int offset; STRING_CHUNK * str_hdr; short int bytes_remaining; short int len; char * p; char * q; bool end_on_value_mark; bool end_on_subvalue_mark; register char c; subvalue_descr = e_stack - 1; value_descr = e_stack - 2; field_descr = e_stack - 3; GetInt(subvalue_descr); subvalue = subvalue_descr->data.value; GetInt(value_descr); value = value_descr->data.value; GetInt(field_descr); field = field_descr->data.value; k_pop(3); /* Set up a string descriptor on our C stack to receive the result */ InitDescr(&result_descr, STRING); result_descr.data.str.saddr = NULL; ts_init(&result_descr.data.str.saddr, 32); if (field <= 0) /* Field zero or negative - Return null string */ { goto done; } else if (value == 0) /* Extracting field */ { end_on_value_mark = FALSE; end_on_subvalue_mark = FALSE; value = 1; subvalue = 1; } else if (subvalue == 0) /* Extracting value */ { end_on_value_mark = TRUE; end_on_subvalue_mark = FALSE; subvalue = 1; } else /* Extracting subvalue */ { end_on_value_mark = TRUE; end_on_subvalue_mark = TRUE; } src_descr = e_stack - 1; k_get_string(src_descr); str_hdr = src_descr->data.str.saddr; if (find_item(str_hdr, field, value, subvalue, &str_hdr, &offset)) { if (str_hdr == NULL) goto done; p = str_hdr->data + offset; bytes_remaining = str_hdr->bytes - offset; while(1) { /* Is there any data left in this chunk? */ if (bytes_remaining) { /* Look for delimiter in the current chunk */ for (q = p; bytes_remaining-- > 0; q++) { c = *q; if ((IsDelim(c)) && ((c == FIELD_MARK) || ((c == VALUE_MARK) && end_on_value_mark) || ((c == SUBVALUE_MARK) && end_on_subvalue_mark))) { /* Copy up to mark */ len = q - p; if (len > 0) ts_copy(p, len); goto done; } } /* Copy remainder of this chunk (must be at least one byte) */ ts_copy(p, q - p); } if ((str_hdr = str_hdr->next) == NULL) break; p = str_hdr->data; bytes_remaining = str_hdr->bytes; } } done: ts_terminate(); k_dismiss(); /* Dismiss source string ADDR */ *(e_stack++) = result_descr; }
Private void rdi( DESCRIPTOR * src_descr, /* Source string */ long int field, long int value, long int subvalue, short int mode, DESCRIPTOR * new_descr, /* Replacement / insertion string */ DESCRIPTOR * result_descr, /* Resultant string */ bool compatible) /* Append style ($MODE COMPATIBLE.APPEND) */ { long int f, v, sv; STRING_CHUNK * str_hdr; short int bytes_remaining; STRING_CHUNK * new_str; short int len; char * p; bool done; char c; char mark; bool mark_skipped = FALSE; bool end_on_value_mark; bool end_on_subvalue_mark; bool item_found; char last_char = '\0'; str_hdr = src_descr->data.str.saddr; /* Set up a string descriptor to receive the result */ InitDescr(result_descr, STRING); result_descr->data.str.saddr = NULL; ts_init(&(result_descr->data.str.saddr), (str_hdr == NULL)?64:str_hdr->string_len); if (field == 0) field = 1; if (value == 0) /* <n, 0, 0> */ { end_on_value_mark = FALSE; end_on_subvalue_mark = FALSE; value = 1; subvalue = 1; mark = FIELD_MARK; } else if (subvalue == 0) /* <n, n, 0> */ { end_on_value_mark = TRUE; end_on_subvalue_mark = FALSE; subvalue = 1; mark = VALUE_MARK; } else /* <n, n, n> */ { end_on_value_mark = TRUE; end_on_subvalue_mark = TRUE; mark = SUBVALUE_MARK; } f = 1; v = 1; sv = 1; /* Current position */ bytes_remaining = 0; /* For null string path */ /* Copy to start of selected item */ if ((field == 1) && (value == 1) && (subvalue == 1)) { /* <1,0,0> or <1,1,0> or <1,1,1> */ if (str_hdr != NULL) { p = str_hdr->data; bytes_remaining = str_hdr->bytes; } item_found = TRUE; goto found; } /* Walk the string to the desired item */ if (str_hdr != NULL) { do { p = str_hdr->data; bytes_remaining = str_hdr->bytes; do { c = *p; if (IsDelim(c)) { switch(c) { case FIELD_MARK: if (f == field) goto not_found; /* No such value or subvalue */ f++; v = 1; sv = 1; break; case VALUE_MARK: if ((f == field) && (v == value)) { goto not_found; /* No such subvalue */ } v++; sv = 1; break; case SUBVALUE_MARK: sv++; break; } if ((f == field) && (v == value) && (sv == subvalue)) { p++; bytes_remaining--; item_found = TRUE; goto found; /* At start position */ } } last_char = c; p++; } while(--bytes_remaining); /* Copy all of source chunk just searched */ ts_copy(str_hdr->data, str_hdr->bytes); } while((str_hdr = str_hdr->next) != NULL); } /* We have reached the end of the string without finding the field we were looking for. */ not_found: found: if (str_hdr != NULL) /* Not run off end of string */ { /* Copy up to current position in source chunk */ len = p - str_hdr->data; if ((mode == DYN_DELETE) && (len > 0) && (c == mark)) /* Don't copy this mark */ { mark_skipped = TRUE; len--; } if (len > 0) ts_copy(str_hdr->data, len); /* Skip old data if we are doing REPLACE or DELETE */ if (item_found) { switch(mode) { case DYN_REPLACE: case DYN_DELETE: done = FALSE; /* Skip old item */ do { /* Is there any data left in this chunk? */ if (bytes_remaining > 0) { /* Look for delimiter in the current chunk */ do { c = *p; if ((IsDelim(c)) && ((c == FIELD_MARK) || ((c == VALUE_MARK) && end_on_value_mark) || ((c == SUBVALUE_MARK) && end_on_subvalue_mark))) { done = TRUE; break; } p++; } while(--bytes_remaining); } if (!done) /* Find next chunk */ { if (str_hdr->next == NULL) done = TRUE; else { str_hdr = str_hdr->next; p = str_hdr->data; bytes_remaining = str_hdr->bytes; } } } while(!done); if ((mode == DYN_DELETE) && !mark_skipped && (c == mark)) { /* Skip the mark too */ p++; bytes_remaining--; } break; } } } /* Insert new data for REPLACE or INSERT */ switch(mode) { case DYN_REPLACE: case DYN_INSERT: /* We may not be at the desired position. For example, if we try to insert <3,2,2> we might not have the necessary number of fields, values or subvalues to get to this position. We must insert marks to get us to the right position. */ if (result_descr->data.str.saddr != NULL) /* Not at start of string */ { if (field < 0) { if (compatible && last_char == FIELD_MARK) { f = 1; /* Kill mark insertion */ field = 1; } else { field = f + 1; /* Insert a single field mark */ } v = 1; sv = 1; } else if (value < 0) { if ((field != f) /* No mark if adding new field... */ || (last_char == FIELD_MARK) /* ... or at start of a field */ || (compatible && last_char == VALUE_MARK)) { v = 1; /* 0222 Set both to one to kill mark insertion */ value = 1; } else value = v + 1; sv = 1; } else if (subvalue < 0) { if ((field != f) /* No mark if adding new field... */ || (value != v) /* ...or adding new value... */ || (last_char == FIELD_MARK) /* ...or at start of a field... */ || (last_char == VALUE_MARK) /* ...or at start of a value */ || (compatible && last_char == SUBVALUE_MARK)) { sv = 1; /* 0222 Set both to one to kill mark insertion */ subvalue = 1; } else subvalue = sv + 1; } } while(f < field) { ts_copy_byte(FIELD_MARK); f++; v = 1; sv = 1; } while(v < value) { ts_copy_byte(VALUE_MARK); v++; sv = 1; } while(sv < subvalue) { ts_copy_byte(SUBVALUE_MARK); sv++; } /* Insert replacement item */ for (new_str = new_descr->data.str.saddr; new_str != NULL; new_str = new_str->next) { ts_copy(new_str->data, new_str->bytes); } /* For insert mode, if we are not at the end of the source string and the next character of the source string is not a mark we must insert a mark to delimit the new data from the following item. */ if ((mode == DYN_INSERT) && (str_hdr != NULL)) { if (bytes_remaining == 0) /* Mark was at end of chunk */ { if ((str_hdr = str_hdr->next) == NULL) goto no_mark_required; p = str_hdr->data; bytes_remaining = str_hdr->bytes; } if ((!IsDelim(*p)) || (*p <= mark)) ts_copy_byte(mark); } no_mark_required: break; } /* Copy remainder of source string */ if (str_hdr != NULL) { /* Is there any data left in this chunk? */ if (bytes_remaining > 0) ts_copy(p, bytes_remaining); /* Copy any remaining chunks */ while((str_hdr = str_hdr->next) != NULL) { ts_copy(str_hdr->data, str_hdr->bytes); } } ts_terminate(); }
bool find_item( STRING_CHUNK * str, long int field, long int value, long int subvalue, STRING_CHUNK ** chunk, short int * offset) { long int f, v, sv; STRING_CHUNK * first_chunk; short int bytes_remaining; char * p; char * q; register char c; long int hint_field; long int hint_offset; long int new_hint_offset = -1; long int skip; if ((field == 1) && (value == 1) && (subvalue == 1)) { /* <1,0,0> or <1,1,0> or <1,1,1> */ *chunk = str; *offset = 0; if (str != NULL) { /* Set hint. This is a bit unfortunate but it simplifies code elsewhere as all calls to find_item() that return true must set the hint to address the item that was found. Having a hint for the start of the string is somewhat unnecessary! */ first_chunk = str; first_chunk->field = 1; first_chunk->offset = 0; } return TRUE; } if (str == NULL) return FALSE; /* Walk the string to the desired item */ first_chunk = str; hint_field = str->field; if ((hint_field) /* Hint present... */ && (hint_field <= field)) /* ...in suitable field */ { /* We have a usable hint to aid location of the desired item */ hint_offset = str->offset; skip = hint_offset; while(skip >= str->bytes) { skip -= str->bytes; if (str->next == NULL) /* Hint points to byte following end of string */ { if ((hint_field == field) /* Right field */ && (value == 1) /* Right value */ && (subvalue == 1)) /* Right subvalue */ { *chunk = str; *offset = str->bytes; return TRUE; } return FALSE; } str = str->next; } hint_offset -= skip; p = str->data + skip; bytes_remaining = (short int)(str->bytes - skip); f = hint_field; } else /* No hint available */ { hint_offset = 0; p = str->data; bytes_remaining = str->bytes; f = 1; } v = 1; sv = 1; if (f < field) { v = 1; do { while(bytes_remaining) { q = (char *)memchr(p, FIELD_MARK, bytes_remaining); if (q == NULL) break; /* No mark in this chunk */ bytes_remaining -= (q - p) + 1; p = q + 1; /* Position after mark */ if (++f == field) goto field_found; } if (str->next == NULL) return FALSE; hint_offset += str->bytes; str = str->next; p = str->data; bytes_remaining = str->bytes; } while(1); } field_found: new_hint_offset = hint_offset + p - str->data; if ((value == v) && (subvalue == 1)) /* At start position */ { goto exit_find_item; } /* Scan for value / subvalue */ while(1) { while(bytes_remaining-- > 0) { c = *(p++); if (IsDelim(c)) { switch(c) { case FIELD_MARK: return FALSE; /* No such value or subvalue */ case VALUE_MARK: if (++v > value) return FALSE; /* No such subvalue */ sv = 1; break; case SUBVALUE_MARK: sv++; break; } if ((v == value) && (sv == subvalue)) /* At start position */ { goto exit_find_item; } } } /* Advance to next chunk */ if (str->next == NULL) break; str = str->next; p = str->data; bytes_remaining = str->bytes; } return FALSE; exit_find_item: *chunk = str; *offset = p - str->data; if (new_hint_offset >= 0) { first_chunk->field = field; first_chunk->offset = new_hint_offset; } return TRUE; }
bool TParser::GetToken(void) { *curToken = '\0'; while(expr[pos]==' ') pos++; if(expr[pos]=='\0') { curToken[0] = '\0'; typToken = PARSER_END; return true; } else if(IsDelim()) { curToken[0] = expr[pos++]; curToken[1] = '\0'; switch(*curToken) { case '+': typToken = PARSER_PLUS; return true; case '-': typToken = PARSER_MINUS; return true; case '*': typToken = PARSER_MULTIPLY; return true; case '/': typToken = PARSER_DIVIDE; return true; case '%': typToken = PARSER_PERCENT; return true; case '^': typToken = PARSER_POWER; return true; case '[': case '(': typToken = PARSER_L_BRACKET; return true; case ']': case ')': typToken = PARSER_R_BRACKET; return true; } } else if(IsLetter()) { int i=0; while(IsLetter()) curToken[i++] = expr[pos++]; curToken[i] = '\0'; int len = strlen(curToken); for(i=0; i<len; i++) if(curToken[i]>='A' && curToken[i]<='Z') curToken[i] += 'a' - 'A'; if(!strcmp(curToken, "x")) { typToken = PARSER_X; return true; } else if(!strcmp(curToken, "pi")) { typToken = PARSER_PI; return true; } else if(!strcmp(curToken, "e")) { typToken = PARSER_E; return true; } else if(!strcmp(curToken, "sin")) { typToken = PARSER_SIN; return true; } else if(!strcmp(curToken, "cos")) { typToken = PARSER_COS; return true; } else if(!strcmp(curToken, "tg")) { typToken = PARSER_TG; return true; } else if(!strcmp(curToken, "ctg")) { typToken = PARSER_CTG; return true; } else if(!strcmp(curToken, "arcsin")) { typToken = PARSER_ARCSIN; return true; } else if(!strcmp(curToken, "arccos")) { typToken = PARSER_ARCCOS; return true; } else if(!strcmp(curToken, "arctg")) { typToken = PARSER_ARCTG; return true; } else if(!strcmp(curToken, "arcctg")) { typToken = PARSER_ARCCTG; return true; } else if(!strcmp(curToken, "sh")) { typToken = PARSER_SH; return true; } else if(!strcmp(curToken, "ch")) { typToken = PARSER_CH; return true; } else if(!strcmp(curToken, "th")) { typToken = PARSER_TH; return true; } else if(!strcmp(curToken, "cth")) { typToken = PARSER_CTH; return true; } else if(!strcmp(curToken, "exp")) { typToken = PARSER_EXP; return true; } else if(!strcmp(curToken, "lg")) { typToken = PARSER_LG; return true; } else if(!strcmp(curToken, "ln")) { typToken = PARSER_LN; return true; } else if(!strcmp(curToken, "sqrt")) { typToken = PARSER_SQRT; return true; } else SendError(0); } else if(IsDigit() || IsPoint()) { int i=0; while(IsDigit()) curToken[i++] = expr[pos++]; if(IsPoint()) { curToken[i++] = expr[pos++]; while(IsDigit()) curToken[i++] = expr[pos++]; } curToken[i] = '\0'; typToken = PARSER_NUMBER; return true; } else { curToken[0] = expr[pos++]; curToken[1] = '\0'; SendError(1); } return false; }
bool TParser::GetToken() { curToken = _T(""); if(pos >= expr.GetLength()) { curToken = _T(""); typToken = PARSER_END; return true; } while(IsSpace()) pos++; if(IsDelim()) { curToken = expr[pos++]; switch(curToken[0]) { case _T('+'): typToken = PARSER_PLUS; return true; case _T('-'): typToken = PARSER_MINUS; return true; case _T('*'): typToken = PARSER_MULTIPLY; return true; case _T('/'): typToken = PARSER_DIVIDE; return true; case _T('%'): typToken = PARSER_PERCENT; return true; case _T('^'): typToken = PARSER_POWER; return true; case _T('['): case _T('('): typToken = PARSER_L_BRACKET; return true; case _T(']'): case _T(')'): typToken = PARSER_R_BRACKET; return true; } } else if(IsComma()) { curToken = expr[pos++]; typToken = PARSER_COMMA; return true; } else if(IsLetter()) { int i=0; curToken = _T(""); while(IsLetter() || IsDigit()) curToken += expr[pos++]; curToken.MakeLower(); if(curToken == _T("pi")) { typToken = PARSER_PI; return true; } else if(curToken == _T("e")) { typToken = PARSER_E; return true; } else if(curToken == _T("sin")) { typToken = PARSER_SIN; return true; } else if(curToken == _T("cos")) { typToken = PARSER_COS; return true; } else if(curToken == _T("tg")) { typToken = PARSER_TG; return true; } else if(curToken == _T("ctg")) { typToken = PARSER_CTG; return true; } else if(curToken == _T("arcsin")) { typToken = PARSER_ARCSIN; return true; } else if(curToken == _T("arccos")) { typToken = PARSER_ARCCOS; return true; } else if(curToken == _T("arctg")) { typToken = PARSER_ARCTG; return true; } else if(curToken == _T("arcctg")) { typToken = PARSER_ARCCTG; return true; } else if(curToken == _T("sh")) { typToken = PARSER_SH; return true; } else if(curToken == _T("ch")) { typToken = PARSER_CH; return true; } else if(curToken == _T("th")) { typToken = PARSER_TH; return true; } else if(curToken == _T("cth")) { typToken = PARSER_CTH; return true; } else if(curToken == _T("exp")) { typToken = PARSER_EXP; return true; } else if(curToken == _T("lg")) { typToken = PARSER_LG; return true; } else if(curToken == _T("ln")) { typToken = PARSER_LN; return true; } else if(curToken == _T("sqrt")) { typToken = PARSER_SQRT; return true; } else if(curToken == _T("abs")) { typToken = PARSER_ABS; return true; } else if(curToken == _T("min")) { typToken = PARSER_MIN; return true; } else if(curToken == _T("max")) { typToken = PARSER_MAX; return true; } else if(curToken == _T("atan2")) { typToken = PARSER_ATAN2; return true; } else if(curToken == _T("if")) { typToken = PARSER_IF; return true; } else if(curToken == _T("left")) { typToken = PARSER_GUIDE; return true; } else if(curToken == _T("right")) { typToken = PARSER_GUIDE; return true; } else if(curToken == _T("top")) { typToken = PARSER_GUIDE; return true; } else if(curToken == _T("bottom")) { typToken = PARSER_GUIDE; return true; } else if(curToken == _T("width")) { typToken = PARSER_GUIDE; return true; } else if(curToken == _T("height")) { typToken = PARSER_GUIDE; return true; } else SendError(0); } else if(IsAdjust()) { int i=0; curToken = _T(""); while((!IsSpace())&&(!IsDelim())) curToken += expr[pos++]; typToken = PARSER_ADJUST; return true; } else if(IsGuide()) { int i=0; curToken = _T(""); while((!IsSpace())&&(!IsDelim())) curToken += expr[pos++]; typToken = PARSER_GUIDE; return true; } else if(IsDigit() || IsPoint()) { int i=0; curToken = _T(""); while(IsDigit()) curToken += expr[pos++]; if(IsPoint()) { curToken += expr[pos++]; while(IsDigit()) curToken += expr[pos++]; } typToken = PARSER_NUMBER; return true; } else { curToken = expr[pos++]; SendError(1); } return false; }
void CUrlRichEditCtrl::ParseAndFormatText(BOOL bForceReformat) { KillTimer(TIMER_REPARSE); AF_NOREENTRANT // prevent reentrancy // parse the control content CString sText; GetWindowText(sText); // richedit2 uses '\r\n' whereas richedit uses just '\n' if (!CWinClasses::IsClass(*this, WC_RICHEDIT)) sText.Replace(_T("\r\n"), _T("\n")); // parse the text into an array of URLPOS CUrlArray aUrls; LPCTSTR szText = sText; BOOL bPrevDelim = TRUE; int nPos = 0; BOOL bBracedFile = FALSE; while (*szText) { // if nChar < 0 then its a multibyte char and can't be part // of a url, so we bump the text buffer by 2 but the pos by 1 #ifndef _UNICODE TCHAR nChar = *szText; if (IsDBCSLeadByte(nChar)) { szText++; szText++; nPos++; continue; } #endif // if the previous item was not a delimiter then there's no // point checking for a protocol match so we just update the // value of bPrevDelim for the current char if (!bPrevDelim) { bPrevDelim = IsDelim(szText); szText++; nPos++; continue; } // if the current char is a delim then this can't be the start // of a url either else if (IsDelim(szText)) { bPrevDelim = TRUE; szText++; nPos++; continue; } // now check for a protocol int nProt = MatchProtocol(szText); // if no match then increment pos and go to next char if (nProt == -1) { bPrevDelim = FALSE; szText++; nPos++; continue; } // check for braces (<...>) if (nPos > 0) bBracedFile = (szText[-1] == '<'); else bBracedFile = FALSE; // find the end of the url (URLDELIMS) int nLen = 0; LPCTSTR szStart = szText; if (bBracedFile) { while (*szText && *szText != '>') { szText++; nLen++; } } else { while (!IsDelim(szText)) { szText++; nLen++; } } bPrevDelim = TRUE; // save the result URLITEM urli; urli.cr.cpMin = nPos; urli.cr.cpMax = urli.cr.cpMin + nLen; nPos += nLen; // make sure the url does not end in a punctuation mark while (ENDPUNCTUATION.Find(szStart[nLen - 1]) != -1) { nLen--; urli.cr.cpMax--; } // Only save if the link is more than just the protocol if (nLen > m_aProtocols[nProt].sProtocol.GetLength()) { urli.sUrl = CString(szStart, nLen); urli.bWantNotify = m_aProtocols[nProt].bWantNotify; InsertInOrder(urli, aUrls); } } // compare aUrls with m_aUrls to see if anything has changed BOOL bReformat = !sText.IsEmpty() && (bForceReformat || !UrlsMatch(aUrls)); // then overwrite (always) m_aUrls.Copy(aUrls); if (bReformat) { BOOL bVisible = IsWindowVisible(); CRePauseUndo rep(*this); if (bVisible) SetRedraw(FALSE); // save current selection CHARRANGE crSel; GetSel(crSel); // and first line int nFirstLine = GetFirstVisibleLine(); // save/reset event mask DWORD dwEventMask = SetEventMask(0); // retrieve default character attribs CHARFORMAT cf; cf.cbSize = sizeof(cf); cf.dwMask = CFM_LINK; // format urls int nUrls = aUrls.GetSize(); CHARRANGE cr = { 0, 0 }; for (int nUrl = 0; nUrl < nUrls; nUrl++) { // clear formatting from the end of the previous // url to the start of this url cr.cpMax = aUrls[nUrl].cr.cpMin; cf.dwEffects = 0; SetSel(cr); SetSelectionCharFormat(cf); // update for next url cr.cpMin = aUrls[nUrl].cr.cpMax; // then format url cf.dwEffects = CFM_LINK; SetSel(aUrls[nUrl].cr); SetSelectionCharFormat(cf); } // clear formatting for whatever's left cr.cpMax = -1; cf.dwEffects = 0; SetSel(cr); SetSelectionCharFormat(cf); // restore selection SetSel(crSel); // and first line SetFirstVisibleLine(nFirstLine); // restore event mask SetEventMask(dwEventMask); if (bVisible) { SetRedraw(TRUE); Invalidate(FALSE); } } }