void Identifier::setFromSql(const wxString& source) { // const wxChar pointers to first and last characters const wxChar* p = source.c_str(); const wxChar* q = p + source.Length() - 1; // skip leading and trailing whitespace while (q > p && wxIsspace(*p)) p++; while (q > p && wxIsspace(*q)) q--; if (p > q) // p is first, q is last character, so they may be equal... { textM = wxEmptyString; return; } // strings/quoted identifier -> strip and unescape single/double quotes if (*q == *p && (*p == '\"' || *p == '\'')) { // NOTE: first parameter must point to first char, but second parameter // has to point to the char *after* the last char !!! textM = wxString(p + 1, q); wxString escapedChar(p, 1); textM.Replace(escapedChar + escapedChar, escapedChar); return; } // set to uppercased input parameter, no leading and trailing whitespace textM = wxString(p, q + 1).Upper(); }
void wxHtmlWordCell::SetPreviousWord(wxHtmlWordCell *cell) { if ( cell && m_Parent == cell->m_Parent && !wxIsspace(cell->m_Word.Last()) && !wxIsspace(m_Word[0u]) ) { m_allowLinebreak = false; } }
void SqlTokenizer::whitespaceToken() { sqlTokenTypeM = tkWHITESPACE; wxASSERT(wxIsspace(*sqlTokenEndM)); sqlTokenEndM++; // scan until non-whitespace, or until "\0" found while (*sqlTokenEndM != 0 && wxIsspace(*sqlTokenEndM)) sqlTokenEndM++; }
void CCManager::DoUpdateCallTip(cbEditor* ed) { wxStringVec tips; int hlStart = m_CurCallTip->hlStart; int hlEnd = m_CurCallTip->hlEnd; size_t sRange = 0; size_t eRange = m_CurCallTip->tip.find(wxT('\n')); while (eRange != wxString::npos) { tips.push_back(m_CurCallTip->tip.Mid(sRange, eRange - sRange)); CCManagerHelper::RipplePts(hlStart, hlEnd, eRange, -1); sRange = eRange + 1; eRange = m_CurCallTip->tip.find(wxT('\n'), sRange); } if (sRange < m_CurCallTip->tip.Length()) tips.push_back(m_CurCallTip->tip.Mid(sRange)); int offset = 0; cbStyledTextCtrl* stc = ed->GetControl(); if (m_CallTips.size() > 1) { ++offset; if (m_CurCallTip == m_CallTips.begin()) tips.front().Prepend(wxT('\002')); // down arrow else if (m_CurCallTip + 1 == m_CallTips.end()) tips.front().Prepend(wxT('\001')); // up arrow else { tips.front().Prepend(wxT("\001\002")); // up/down arrows ++offset; } tips.push_back(wxString::Format(wxT("(%d/%u)"), m_CurCallTip - m_CallTips.begin() + 1, m_CallTips.size())); // store for better first choice later m_CallTipChoiceDict[CCManagerHelper::CallTipToInt(m_CallTips.front().tip, m_CallTips.size())] = m_CurCallTip - m_CallTips.begin(); // fuzzy store int prefixEndPos = m_CallTipActive; while (prefixEndPos > 0 && wxIsspace(stc->GetCharAt(prefixEndPos - 1))) --prefixEndPos; const wxString& prefix = stc->GetTextRange(stc->WordStartPosition(prefixEndPos, true), prefixEndPos); m_CallTipFuzzyChoiceDict[CCManagerHelper::CallTipToInt(prefix, m_CallTips.size())] = m_CurCallTip - m_CallTips.begin(); } int pos = stc->GetCurrentPos(); int lnStart = stc->PositionFromLine(stc->LineFromPosition(pos)); while (wxIsspace(stc->GetCharAt(lnStart))) ++lnStart; #ifdef __WXMSW__ m_LastTipPos = wxSCI_INVALID_POSITION; // Windows hack to fix display update #endif // __WXMSW__ DoShowTips(tips, stc, std::max(pos, lnStart), m_CallTipActive, hlStart + offset, hlEnd + offset); }
void wxStringTokenizer::SetString(const wxString& str, const wxString& delims, wxStringTokenizerMode mode) { if ( mode == wxTOKEN_DEFAULT ) { // by default, we behave like strtok() if the delimiters are only // whitespace characters and as wxTOKEN_RET_EMPTY otherwise (for // whitespace delimiters, strtok() behaviour is better because we want // to count consecutive spaces as one delimiter) const wxChar *p; for ( p = delims.c_str(); *p; p++ ) { if ( !wxIsspace(*p) ) break; } if ( *p ) { // not whitespace char in delims mode = wxTOKEN_RET_EMPTY; } else { // only whitespaces mode = wxTOKEN_STRTOK; } } m_delims = delims; m_mode = mode; Reinit(str); }
void SqlTokenizer::defaultToken() { if (wxStricmp(sqlTokenStartM, termM.c_str()) == 0) { sqlTokenTypeM = tkTERM; sqlTokenEndM = sqlTokenStartM + termM.Length(); return; } // this is needed for new terminator string while (true) { // increase the size until we hit either whitespace, terminator, EOF // or some of significant characters sqlTokenEndM++; if (*sqlTokenEndM == 0 || *sqlTokenEndM == ',' || *sqlTokenEndM == '=' || *sqlTokenEndM == '(' || *sqlTokenEndM == ')' || *sqlTokenEndM == '+' || *sqlTokenEndM == '-' || *sqlTokenEndM == '/' || *sqlTokenEndM == '*' || wxIsspace(*sqlTokenEndM) || wxStricmp(sqlTokenEndM, termM.c_str()) == 0 ) { break; } } sqlTokenTypeM = tkUNKNOWN; }
bool SqlTokenizer::nextToken() { sqlTokenStartM = sqlTokenEndM; if (sqlTokenEndM == 0 || *sqlTokenEndM == 0) { sqlTokenTypeM = tkEOF; return false; } // use wxChar* member to scan wxChar c = *sqlTokenEndM; if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) keywordIdentifierToken(); else if (c == '"') quotedIdentifierToken(); else if (c == '\'') stringToken(); else if (c == '(') symbolToken(tkPARENOPEN); else if (c == ')') symbolToken(tkPARENCLOSE); else if (c == '=') symbolToken(tkEQUALS); else if (c == ',') symbolToken(tkCOMMA); else if (c == '/' && *(sqlTokenEndM + 1) == '*') multilineCommentToken(); else if (c == '-' && *(sqlTokenEndM + 1) == '-') singleLineCommentToken(); else if (wxIsspace(c)) whitespaceToken(); else defaultToken(); return true; }
HighlightLanguage EditorColourSet::AddHighlightLanguage(int lexer, const wxString& name) { if ( lexer <= wxSCI_LEX_NULL || lexer > wxSCI_LEX_LAST // this is a C::B extension to wxscintilla.h || name.IsEmpty() ) { return HL_NONE; } // fix name to be XML compliant wxString newID; size_t pos = 0; while (pos < name.Length()) { wxChar ch = name[pos]; if (wxIsalnum(ch) || ch == _T('_')) newID.Append(ch); // valid character else if (wxIsspace(ch)) newID.Append(_T('_')); // convert spaces to underscores ++pos; } // make sure it's not starting with a number or underscore. // if it is, prepend an 'A' if (wxIsdigit(newID.GetChar(0)) || newID.GetChar(0) == _T('_')) newID.Prepend(_T('A')); if (GetHighlightLanguage(newID) != HL_NONE) return HL_NONE; m_Sets[newID].m_Langs = name; m_Sets[newID].m_Lexers = lexer; return newID; }
bool wxExtHelpController::ParseMapFileLine(const wxString& line) { const wxChar *p = line.c_str(); // skip whitespace while ( isascii(*p) && wxIsspace(*p) ) p++; // skip empty lines and comments if ( *p == wxT('\0') || *p == WXEXTHELP_COMMENTCHAR ) return true; // the line is of the form "num url" so we must have an integer now wxChar *end; const unsigned long id = wxStrtoul(p, &end, 0); if ( end == p ) return false; p = end; while ( isascii(*p) && wxIsspace(*p) ) p++; // next should be the URL wxString url; url.reserve(line.length()); while ( isascii(*p) && !wxIsspace(*p) ) url += *p++; while ( isascii(*p) && wxIsspace(*p) ) p++; // and finally the optional description of the entry after comment wxString doc; if ( *p == WXEXTHELP_COMMENTCHAR ) { p++; while ( isascii(*p) && wxIsspace(*p) ) p++; doc = p; } m_MapList->Append(new wxExtHelpMapEntry(id, url, doc)); m_NumOfEntries++; return true; }
void ClangCodeCompletion::HighlightOccurrences(cbEditor* ed) { ClTranslUnitId translId = GetCurrentTranslationUnitId(); cbStyledTextCtrl* stc = ed->GetControl(); int pos = stc->GetCurrentPos(); const wxChar ch = stc->GetCharAt(pos); if (pos > 0 && (wxIsspace(ch) || (ch != wxT('_') && wxIspunct(ch))) && !wxIsspace(stc->GetCharAt(pos - 1))) { --pos; } // chosen a high value for indicator, hoping not to interfere with the indicators used by some lexers // if they get updated from deprecated old style indicators someday. const int theIndicator = 16; stc->SetIndicatorCurrent(theIndicator); // Set Styling: // clear all style indications set in a previous run (is also done once after text gets unselected) stc->IndicatorClearRange(0, stc->GetLength()); if (stc->GetTextRange(pos - 1, pos + 1).Strip().IsEmpty()) return; // TODO: use independent key wxColour highlightColour(Manager::Get()->GetColourManager()->GetColour(wxT("editor_highlight_occurrence"))); stc->IndicatorSetStyle(theIndicator, wxSCI_INDIC_HIGHLIGHT); stc->IndicatorSetForeground(theIndicator, highlightColour); stc->IndicatorSetUnder(theIndicator, true); const int line = stc->LineFromPosition(pos); ClTokenPosition loc(line + 1, pos - stc->PositionFromLine(line) + 1); std::vector< std::pair<int, int> > occurrences; m_pClangPlugin->GetOccurrencesOf( translId, ed->GetFilename(), loc, 100, occurrences ); for (std::vector< std::pair<int, int> >::const_iterator tkn = occurrences.begin(); tkn != occurrences.end(); ++tkn) { stc->IndicatorFillRange(tkn->first, tkn->second); } }
// quote the string before writing it to file static wxString FilterOutValue(const wxString& str) { if ( !str ) return str; wxString strResult; strResult.Alloc(str.Len()); // quoting is necessary to preserve spaces in the beginning of the string bool bQuote = wxIsspace(str[0]) || str[0] == wxT('"'); if ( bQuote ) strResult += wxT('"'); wxChar c; for ( size_t n = 0; n < str.Len(); n++ ) { switch ( str[n] ) { case wxT('\n'): c = wxT('n'); break; case wxT('\r'): c = wxT('r'); break; case wxT('\t'): c = wxT('t'); break; case wxT('\\'): c = wxT('\\'); break; case wxT('"'): if ( bQuote ) { c = wxT('"'); break; } //else: fall through default: strResult += str[n]; continue; // nothing special to do } // we get here only for special characters strResult << wxT('\\') << c; } if ( bQuote ) strResult += wxT('"'); return strResult; }
void strutil_delwhitespace(String &str) { String newstr = wxEmptyString; const wxChar *cptr = str.c_str(); while(wxIsspace(*cptr)) cptr++; while(*cptr) newstr += *cptr++; str = newstr; }
bool wxPropertyValidator::StringToLong (wxChar *s, long *number) { bool ok = true; wxChar *value_ptr; *number = wxStrtol (s, &value_ptr, 10); if (value_ptr) { int len = wxStrlen (value_ptr); for (int i = 0; i < len; i++) { ok = (wxIsspace (value_ptr[i]) != 0); if (!ok) return false; } } return ok; }
void cbStyledTextCtrl::DoBraceCompletion(const wxChar& ch) { const int pos = GetCurrentPos(); const int style = GetStyleAt(pos); if (IsComment(style) || IsComment(GetStyleAt(pos - 2))) return; // do nothing if (ch == wxT('\'') || ch == wxT('"')) { if (GetCharAt(pos) == ch) { DeleteBack(); CharRight(); } else if (!IsString(GetStyleAt(pos - 2)) && !IsCharacter(GetStyleAt(pos - 2))) InsertText(pos, ch); return; // done } if (IsString(style) || IsCharacter(style)) return; // do nothing const wxString opBraces(wxT("([{")); const int opBraceIdx = opBraces.Find(ch); const wxString clBraces(wxT(")]}")); const int clBraceIdx = clBraces.Find(ch); if ( (opBraceIdx != wxNOT_FOUND) || (clBraceIdx != wxNOT_FOUND) ) { if ( GetCharAt(pos) == ch ) { DeleteBack(); CharRight(); } else if (opBraceIdx != wxNOT_FOUND) { int nextPos = pos; while ( wxIsspace(GetCharAt(nextPos)) && (nextPos < GetLength()) ) ++nextPos; if ( ((wxChar)GetCharAt(nextPos) != clBraces[opBraceIdx]) || (BraceMatch(nextPos) != wxNOT_FOUND) ) { InsertText(pos, clBraces[opBraceIdx]); } } } }
void wxStringTokenizer::SetString(const wxString& str, const wxString& delims, wxStringTokenizerMode mode) { if ( mode == wxTOKEN_DEFAULT ) { // by default, we behave like strtok() if the delimiters are only // whitespace characters and as wxTOKEN_RET_EMPTY otherwise (for // whitespace delimiters, strtok() behaviour is better because we want // to count consecutive spaces as one delimiter) wxString::const_iterator p; for ( p = delims.begin(); p != delims.end(); ++p ) { if ( !wxIsspace(*p) ) break; } if ( p != delims.end() ) { // not whitespace char in delims mode = wxTOKEN_RET_EMPTY; } else { // only whitespaces mode = wxTOKEN_STRTOK; } } #if wxUSE_UNICODE // FIXME-UTF8: only wc_str() m_delims = delims.wc_str(); #else m_delims = delims.mb_str(); #endif m_delimsLen = delims.length(); m_mode = mode; Reinit(str); }
void Compiler::MakeValidID() { // basically, make it XML-element compatible // only allow a-z, 0-9 and _ // (it is already lowercase) // any non-conformant character will be removed wxString newID; if (m_ID.IsEmpty()) m_ID = m_Name; size_t pos = 0; while (pos < m_ID.Length()) { wxChar ch = m_ID[pos]; if (wxIsalnum(ch) || ch == _T('_')) // valid character newID.Append(ch); else if (wxIsspace(ch)) // convert spaces to underscores newID.Append(_T('_')); ++pos; } // make sure it's not starting with a number. // if it is, prepend "cb" if (wxIsdigit(newID.GetChar(0))) newID.Prepend(_T("cb")); if (newID.IsEmpty()) // empty? wtf? cbThrow(_T("Can't create a valid compiler ID for ") + m_Name); m_ID = newID.Lower(); // check for unique ID if (!IsUniqueID(m_ID)) cbThrow(_T("Compiler ID already exists for ") + m_Name); m_CompilerIDs.Add(m_ID); }
std::vector<cbCodeCompletionPlugin::CCToken> ClangCodeCompletion::GetAutocompList(bool isAuto, cbEditor* ed, int& tknStart, int& tknEnd) { #ifdef CLANGPLUGIN_TRACE_FUNCTIONS fprintf(stdout,"%s isAuto=%d\n", __PRETTY_FUNCTION__,(int)isAuto); #endif std::vector<cbCodeCompletionPlugin::CCToken> tokens; int CCOutstanding = m_CCOutstanding; if ((CCOutstanding > 0)&&(m_CCOutstandingPos != ed->GetControl()->GetCurrentPos())) { CCOutstanding = 0; } m_CCOutstanding = 0; ClTranslUnitId translUnitId = m_TranslUnitId; if( translUnitId != GetCurrentTranslationUnitId() ) return tokens; if (translUnitId == wxNOT_FOUND) { Manager::Get()->GetLogManager()->LogWarning(wxT("ClangLib: m_TranslUnitId == wxNOT_FOUND, " "cannot complete in file ") + ed->GetFilename()); return tokens; } cbStyledTextCtrl* stc = ed->GetControl(); const int style = stc->GetStyleAt(tknEnd); const wxChar curChar = stc->GetCharAt(tknEnd - 1); if (isAuto) // filter illogical cases of auto-launch { if ((curChar == wxT(':') // scope operator && stc->GetCharAt(tknEnd - 2) != wxT(':') ) || ( curChar == wxT('>') // '->' && stc->GetCharAt(tknEnd - 2) != wxT('-') ) || ( wxString(wxT("<\"/")).Find(curChar) != wxNOT_FOUND // #include directive (TODO: enumerate completable include files) && !stc->IsPreprocessor(style))) { return tokens; } } const int line = stc->LineFromPosition(tknStart); /* std::map<wxString, wxString> unsavedFiles; EditorManager* edMgr = Manager::Get()->GetEditorManager(); for (int i = 0; i < edMgr->GetEditorsCount(); ++i) { cbEditor* editor = edMgr->GetBuiltinEditor(i); if (editor && editor->GetModified()) unsavedFiles.insert(std::make_pair(editor->GetFilename(), editor->GetControl()->GetText())); } */ const int lnStart = stc->PositionFromLine(line); int column = tknStart - lnStart; for (; column > 0; --column) { if (!wxIsspace(stc->GetCharAt(lnStart + column - 1)) || (column != 1 && !wxIsspace(stc->GetCharAt(lnStart + column - 2)))) { break; } } const wxString& prefix = stc->GetTextRange(tknStart, tknEnd).Lower(); bool includeCtors = true; // sometimes we get a lot of these for (int i = tknStart - 1; i > 0; --i) { wxChar chr = stc->GetCharAt(i); if (!wxIsspace(chr)) { if (chr == wxT(';') || chr == wxT('}')) // last non-whitespace character includeCtors = false; // filter out ctors (they are unlikely to be wanted in this situation) break; } } std::vector<ClToken> tknResults; if ((CCOutstanding == 0)||(m_CCOutstandingResults.size()==0)) { ClTokenPosition loc(line+1, column+1); //ClangProxy::CodeCompleteAtJob job( cbEVT_CLANG_SYNCTASK_FINISHED, idClangCodeCompleteTask, isAuto, ed->GetFilename(), loc, m_TranslUnitId, unsavedFiles); //m_Proxy.AppendPendingJob(job); unsigned long timeout = 40; if( !isAuto ) { timeout = 500; } if( wxCOND_TIMEOUT == m_pClangPlugin->GetCodeCompletionAt(translUnitId, ed->GetFilename(), loc, timeout, tknResults)) { if (wxGetLocalTime() - m_CCOutstandingLastMessageTime > 10) { //InfoWindow::Display(_("Code completion"), _("Busy parsing the document"), 1000); m_CCOutstandingLastMessageTime = wxGetLocalTime(); } //std::cout<<"Timeout waiting for code completion"<<std::endl; m_CCOutstanding++; m_CCOutstandingPos = ed->GetControl()->GetCurrentPos(); m_CCOutstandingResults.clear(); return tokens; } } else { tknResults = m_CCOutstandingResults; } //m_Proxy.CodeCompleteAt(isAuto, ed->GetFilename(), line + 1, column + 1, // m_TranslUnitId, unsavedFiles, tknResults); if (prefix.Length() > 3) // larger context, match the prefix at any point in the token { for (std::vector<ClToken>::const_iterator tknIt = tknResults.begin(); tknIt != tknResults.end(); ++tknIt) { if (tknIt->name.Lower().Find(prefix) != wxNOT_FOUND && (includeCtors || tknIt->category != tcCtorPublic)) tokens.push_back(cbCodeCompletionPlugin::CCToken(tknIt->id, tknIt->name, tknIt->name, tknIt->weight, tknIt->category)); } } else if (prefix.IsEmpty()) { for (std::vector<ClToken>::const_iterator tknIt = tknResults.begin(); tknIt != tknResults.end(); ++tknIt) { // it is rather unlikely for an operator to be the desired completion if (!tknIt->name.StartsWith(wxT("operator")) && (includeCtors || tknIt->category != tcCtorPublic)) tokens.push_back(cbCodeCompletionPlugin::CCToken(tknIt->id, tknIt->name, tknIt->name, tknIt->weight, tknIt->category)); } } else // smaller context, only allow matches of the prefix at the beginning of the token { for (std::vector<ClToken>::const_iterator tknIt = tknResults.begin(); tknIt != tknResults.end(); ++tknIt) { if (tknIt->name.Lower().StartsWith(prefix) && (includeCtors || tknIt->category != tcCtorPublic)) tokens.push_back(cbCodeCompletionPlugin::CCToken(tknIt->id, tknIt->name, tknIt->name, tknIt->weight, tknIt->category)); } } if (!tokens.empty()) { if (prefix.IsEmpty() && tokens.size() > 1500) // reduce to give only top matches { std::partial_sort(tokens.begin(), tokens.begin() + 1000, tokens.end(), PrioritySorter()); tokens.erase(tokens.begin() + 1000, tokens.end()); } const int imgCount = m_pClangPlugin->GetImageList(translUnitId).GetImageCount(); for (int i = 0; i < imgCount; ++i) stc->RegisterImage(i, m_pClangPlugin->GetImageList(translUnitId).GetBitmap(i)); bool isPP = stc->GetLine(line).Strip(wxString::leading).StartsWith(wxT("#")); std::set<int> usedWeights; for (std::vector<cbCodeCompletionPlugin::CCToken>::iterator tknIt = tokens.begin(); tknIt != tokens.end(); ++tknIt) { wxStringVec keywords = m_pClangPlugin->GetKeywords(translUnitId); usedWeights.insert(tknIt->weight); switch (tknIt->category) { case tcNone: if (isPP) tknIt->category = tcMacroDef; else if (std::binary_search(keywords.begin(), keywords.end(), GetActualName(tknIt->name))) tknIt->category = tcLangKeyword; break; case tcClass: case tcCtorPublic: case tcDtorPublic: case tcFuncPublic: case tcVarPublic: case tcEnum: case tcTypedef: // TODO //m_Proxy.RefineTokenType(m_TranslUnitId, tknIt->id, tknIt->category); break; default: break; } } // Clang sometimes gives many weight values, which can make completion more difficult // because results are less alphabetical. Use a compression map on the lower priority // values (higher numbers) to reduce the total number of weights used. if (usedWeights.size() > 3) { std::vector<int> weightsVec(usedWeights.begin(), usedWeights.end()); std::map<int, int> weightCompr; weightCompr[weightsVec[0]] = weightsVec[0]; weightCompr[weightsVec[1]] = weightsVec[1]; int factor = (weightsVec.size() > 7 ? 3 : 2); for (size_t i = 2; i < weightsVec.size(); ++i) weightCompr[weightsVec[i]] = weightsVec[(i - 2) / factor + 2]; for (std::vector<cbCodeCompletionPlugin::CCToken>::iterator tknIt = tokens.begin(); tknIt != tokens.end(); ++tknIt) { tknIt->weight = weightCompr[tknIt->weight]; } } } std::cout<<"CodeCompletion finished"<<std::endl; return tokens; }
// cbEVT_SHOW_CALL_TIP void CCManager::OnShowCallTip(CodeBlocksEvent& event) { event.Skip(); cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor(); if (!ed) return; cbCodeCompletionPlugin* ccPlugin = GetProviderFor(ed); if (!ccPlugin) return; cbStyledTextCtrl* stc = ed->GetControl(); int pos = stc->GetCurrentPos(); int argsPos = wxSCI_INVALID_POSITION; wxString curTip; if (!m_CallTips.empty()) curTip = m_CurCallTip->tip; m_CallTips = ccPlugin->GetCallTips(pos, stc->GetStyleAt(pos), ed, argsPos); if (!m_CallTips.empty() && (event.GetInt() != FROM_TIMER || argsPos == m_CallTipActive)) { int lnStart = stc->PositionFromLine(stc->LineFromPosition(pos)); while (wxIsspace(stc->GetCharAt(lnStart))) ++lnStart; // do not show too far left on multi-line call tips if ( m_CallTips.size() > 1 && !Manager::Get()->GetConfigManager(wxT("ccmanager"))->ReadBool(wxT("multi_page_tips"), true) ) { wxString tip; int hlStart, hlEnd; hlStart = hlEnd = wxSCI_INVALID_POSITION; for (CallTipVec::const_iterator itr = m_CallTips.begin(); itr != m_CallTips.end(); ++itr) { if (hlStart == hlEnd && itr->hlStart != itr->hlEnd) { hlStart = tip.Length() + itr->hlStart; hlEnd = tip.Length() + itr->hlEnd; } tip += itr->tip + wxT('\n'); } m_CallTips.clear(); m_CallTips.push_back(cbCodeCompletionPlugin::CCCallTip(tip.RemoveLast(), hlStart, hlEnd)); } m_CurCallTip = m_CallTips.begin(); if (m_CallTips.size() > 1) { // search long term recall std::map<int, size_t>::const_iterator choiceItr = m_CallTipChoiceDict.find(CCManagerHelper::CallTipToInt(m_CurCallTip->tip, m_CallTips.size())); if (choiceItr != m_CallTipChoiceDict.end() && choiceItr->second < m_CallTips.size()) m_CurCallTip = m_CallTips.begin() + choiceItr->second; if (choiceItr == m_CallTipChoiceDict.end() || argsPos == m_CallTipActive) { int prefixEndPos = argsPos; while (prefixEndPos > 0 && wxIsspace(stc->GetCharAt(prefixEndPos - 1))) --prefixEndPos; const wxString& prefix = stc->GetTextRange(stc->WordStartPosition(prefixEndPos, true), prefixEndPos); choiceItr = m_CallTipFuzzyChoiceDict.find(CCManagerHelper::CallTipToInt(prefix, m_CallTips.size())); if (choiceItr != m_CallTipFuzzyChoiceDict.end() && choiceItr->second < m_CallTips.size()) m_CurCallTip = m_CallTips.begin() + choiceItr->second; } // search short term recall for (CallTipVec::const_iterator itr = m_CallTips.begin(); itr != m_CallTips.end(); ++itr) { if (itr->tip == curTip) { m_CurCallTip = itr; break; } } } m_CallTipActive = argsPos; DoUpdateCallTip(ed); } else if (m_CallTipActive != wxSCI_INVALID_POSITION) { static_cast<wxScintilla*>(stc)->CallTipCancel(); m_CallTipActive = wxSCI_INVALID_POSITION; } }
wxInt32 NaturalCompare(wxString String1, wxString String2, bool CaseSensitive = false) { wxInt32 StringCounter1 = 0, StringCounter2 = 0; wxInt32 String1Zeroes = 0, String2Zeroes = 0; wxChar String1Char, String2Char; wxInt32 Result; if (!CaseSensitive) { String1.MakeLower(); String2.MakeLower(); } while (true) { String1Zeroes = 0; String2Zeroes = 0; String1Char = String1[StringCounter1]; String2Char = String2[StringCounter2]; // skip past whitespace or zeroes in first string while (wxIsspace(String1Char) || String1Char == '0' ) { if (String1Char == '0') { String1Zeroes++; } else { String1Zeroes = 0; } String1Char = String1[++StringCounter1]; } // skip past whitespace or zeroes in second string while (wxIsspace(String2Char) || String2Char == '0') { if (String2Char == '0') { String2Zeroes++; } else { String2Zeroes = 0; } String2Char = String2[++StringCounter2]; } // We encountered some digits, compare these. if (wxIsdigit(String1Char) && wxIsdigit(String2Char)) { if ((Result = NaturalCompareWorker( String1.Mid(StringCounter1), String2.Mid(StringCounter2))) != 0) { return Result; } } if ((String1Char == 0) && (String2Char == 0)) { return (String1Zeroes - String2Zeroes); } if (String1Char < String2Char) { return -1; } else if (String1Char > String2Char) { return 1; } ++StringCounter1; ++StringCounter2; } }
int URLDetector::FindURL(const wxChar *text, int& len) { // offset of the current value of text from the initial one int offset = 0; match: int pos = scan(text, len); if ( !len ) return -1; // the provisional start and end of the URL, will be changed below const wxChar *start = text + pos; const wxChar *p = start + len; // there are 2 different cases: a mailto: URL or a mail address and // anything else which we need to treat differently bool isMail = *start == '@'; if ( isMail ) { // look for the start of the address start--; while ( start > text && IsLocalPartChar(*start) ) start--; // have we stopped at '<'? bool hasAngleBracket = *start == '<'; if ( !hasAngleBracket ) { if ( !IsLocalPartChar(*start) ) { // we went too far backwards start++; } //else: we stopped at the start of the text } //else: keep '<' as part of the URL // now look for the end of it while ( *p && IsDomainChar(*p) ) { p++; } // finally we should either have the brackets from both sides or none // at all if ( hasAngleBracket ) { if ( *p == '>' ) { // take the right bracket as well p++; } else { // forget about the left one start++; } } } else // !bare mail address { for ( ;; ) { size_t lenURL = 0; while ( IsURLChar(*p) ) { lenURL++; p++; } // URLs are frequently so long that they're spread across multiple // lines, so try to see if this might be the case here // // first of all we need to check whether it is at the end of line but // we should allow some trailing spaces const wxChar* q = p; while ( *q == ' ' ) q++; if ( q[0] != '\r' || q[1] != '\n' ) break; // not at the line end // also check if it's really long enough to be wrapped: // the short URLs normally shouldn't be wrapped static const size_t URL_WRAP_LEN = 30; // min len of wrapped URL if ( lenURL < URL_WRAP_LEN ) break; // too short if ( !IsURLChar(q[2]) ) break; // doesn't seem to be continued on the next line // heuristic text for end of URL detection if ( p - start > 5 && !CanBeWrapped(p) ) { // it seems that the URL ends here break; } p = q + 2; // go to the start of next line // Check that the beginning of next line is not the start of // another URL. // // Note that although '@' alone is recognized as the beginning // of an URL: here it should not be the case. int nextlen = 0; int nextpos = scan(p, nextlen); if ( nextlen && nextpos == 0 && *p != '@') { p -= 2; // The start of the next line being the start of an URL on its own, // do not join the two. break; } // check whether the next line starts with a word -- this is a good // indication that the URL hasn't wrapped q = p; while ( wxIsalpha(*q) ) q++; if ( *q == _T(' ') || (wxStrchr(_T(".,:;"), *q) && q[1] == _T(' ')) ) { // looks like we've a word (i.e. sequence of letters terminated by // space or punctuation) at the start of the next line p -= 2; break; } // another special case: subsequent dashes are very unusual in URLs // but often used as separator lines, so we assume that they indicate // the end of the URL if we find them on the next line. if ( p[0] == '-' && p[1] == '-' ) break; // it might be a wrapped URL but it might be not: it seems like we // get way too many false positives if we suppose that it's always // the case... so restrict the wrapped URLs detection to the case // when they occur at the beginning of the line, possibly after some // white space as this is how people usually format them q = start; while ( q >= text && *q != '\n' ) { q--; if ( !wxIsspace(*q) ) break; } // Does the URL start at the beginning of the line, or does it have // a '<' just in front? if ( q >= text && *q != '\n' && *q != '<') break; // it did occur at the start (or after '<'), suppose the URL is // wrapped and so we continue on the next line (and no need to test // the first character, it had been already done above) p++; } } // truncate any punctuation at the end while ( strchr(".:,)]!?", *(p - 1)) ) p--; // additional checks for the matches which didn't have an explicit scheme if ( isMail || text[pos + len - 3 /* len of "://" */ ] != _T(':') ) { // '@' matches may result in false positives, as not every '@' character // is inside a mailto URL so try to weed them out by requiring that the // mail address has a reasonable minimal length ("*****@*****.**" and // "www.xy.fr" are probably the shortest ones we can have, hence 8) // which at least avoids matching the bare '@'s bool good = (p - start) >= 8; if ( good ) { // also check that we have at least one dot in the domain part for the // mail addresses const wxChar * pDot = wxTmemchr(text + pos + 1, '.', p - text - pos - 1); if ( !pDot ) { good = false; } else if ( !isMail ) { // and has either two dots or at least a slash the other URLs, // otherwise it probably isn't an address/URL neither (stuff like // "... using ftp.If you ... " shouldn't be recognized as an URL) good = wxTmemchr(pDot + 1, '.', p - pDot - 1) != NULL || wxTmemchr(pDot + 1, '/', p - pDot - 1) != NULL; } } if ( !good ) { const int offDiff = pos + len; offset += offDiff; text += offDiff; // slightly more efficient than recursion... goto match; } } // return the length of the match len = p - start; return start - text + offset; }
std::vector<ClangPlugin::CCToken> ClangPlugin::GetAutocompList(bool isAuto, cbEditor* ed, int& tknStart, int& tknEnd) { std::vector<CCToken> tokens; if (ed != m_pLastEditor) { m_TranslUnitId = m_Proxy.GetTranslationUnitId(ed->GetFilename()); m_pLastEditor = ed; } if (m_TranslUnitId == wxNOT_FOUND) { Manager::Get()->GetLogManager()->LogWarning(wxT("ClangLib: m_TranslUnitId == wxNOT_FOUND, cannot complete in file ") + ed->GetFilename()); return tokens; } cbStyledTextCtrl* stc = ed->GetControl(); const int style = stc->GetStyleAt(tknEnd); const wxChar curChar = stc->GetCharAt(tknEnd - 1); if (isAuto) // filter illogical cases of auto-launch { if ( ( curChar == wxT(':') // scope operator && stc->GetCharAt(tknEnd - 2) != wxT(':') ) || ( curChar == wxT('>') // '->' && stc->GetCharAt(tknEnd - 2) != wxT('-') ) || ( wxString(wxT("<\"/")).Find(curChar) != wxNOT_FOUND // #include directive (TODO: enumerate completable include files) && !stc->IsPreprocessor(style) ) ) { return tokens; } } std::vector<ClToken> tknResults; const int line = stc->LineFromPosition(tknStart); std::map<wxString, wxString> unsavedFiles; EditorManager* edMgr = Manager::Get()->GetEditorManager(); for (int i = 0; i < edMgr->GetEditorsCount(); ++i) { cbEditor* editor = edMgr->GetBuiltinEditor(i); if (editor && editor->GetModified()) unsavedFiles.insert(std::make_pair(editor->GetFilename(), editor->GetControl()->GetText())); } const int lnStart = stc->PositionFromLine(line); int column = tknStart - lnStart; for (; column > 0; --column) { if ( !wxIsspace(stc->GetCharAt(lnStart + column - 1)) || (column != 1 && !wxIsspace(stc->GetCharAt(lnStart + column - 2))) ) { break; } } m_Proxy.CodeCompleteAt(isAuto, ed->GetFilename(), line + 1, column + 1, m_TranslUnitId, unsavedFiles, tknResults); const wxString& prefix = stc->GetTextRange(tknStart, tknEnd).Lower(); bool includeCtors = true; // sometimes we get a lot of these for (int i = tknStart - 1; i > 0; --i) { wxChar chr = stc->GetCharAt(i); if (!wxIsspace(chr)) { if (chr == wxT(';') || chr == wxT('}')) // last non-whitespace character includeCtors = false; // filter out ctors (they are unlikely to be wanted in this situation) break; } } if (prefix.Length() > 3) // larger context, match the prefix at any point in the token { for (std::vector<ClToken>::const_iterator tknIt = tknResults.begin(); tknIt != tknResults.end(); ++tknIt) { if (tknIt->name.Lower().Find(prefix) != wxNOT_FOUND && (includeCtors || tknIt->category != tcCtorPublic)) tokens.push_back(CCToken(tknIt->id, tknIt->name, tknIt->name, tknIt->weight, tknIt->category)); } } else if (prefix.IsEmpty()) { for (std::vector<ClToken>::const_iterator tknIt = tknResults.begin(); tknIt != tknResults.end(); ++tknIt) { if (!tknIt->name.StartsWith(wxT("operator")) && (includeCtors || tknIt->category != tcCtorPublic)) // it is rather unlikely for an operator to be the desired completion tokens.push_back(CCToken(tknIt->id, tknIt->name, tknIt->name, tknIt->weight, tknIt->category)); } } else // smaller context, only allow matches of the prefix at the beginning of the token { for (std::vector<ClToken>::const_iterator tknIt = tknResults.begin(); tknIt != tknResults.end(); ++tknIt) { if (tknIt->name.Lower().StartsWith(prefix) && (includeCtors || tknIt->category != tcCtorPublic)) tokens.push_back(CCToken(tknIt->id, tknIt->name, tknIt->name, tknIt->weight, tknIt->category)); } } if (!tokens.empty()) { if (prefix.IsEmpty() && tokens.size() > 1500) // reduce to give only top matches { std::partial_sort(tokens.begin(), tokens.begin() + 1000, tokens.end(), PrioritySorter()); tokens.erase(tokens.begin() + 1000, tokens.end()); } const int imgCount = m_ImageList.GetImageCount(); for (int i = 0; i < imgCount; ++i) stc->RegisterImage(i, m_ImageList.GetBitmap(i)); bool isPP = stc->GetLine(line).Strip(wxString::leading).StartsWith(wxT("#")); std::set<int> usedWeights; for (std::vector<CCToken>::iterator tknIt = tokens.begin(); tknIt != tokens.end(); ++tknIt) { usedWeights.insert(tknIt->weight); switch (tknIt->category) { case tcNone: if (isPP) tknIt->category = tcMacroDef; else if (std::binary_search(m_CppKeywords.begin(), m_CppKeywords.end(), GetActualName(tknIt->name))) tknIt->category = tcLangKeyword; break; case tcClass: case tcCtorPublic: case tcDtorPublic: case tcFuncPublic: case tcVarPublic: case tcEnum: case tcTypedef: m_Proxy.RefineTokenType(m_TranslUnitId, tknIt->id, tknIt->category); break; default: break; } } // Clang sometimes gives many weight values, which can make completion more difficult // because results are less alphabetical. Use a compression map on the lower priority // values (higher numbers) to reduce the total number of weights used. if (usedWeights.size() > 3) { std::vector<int> weightsVec(usedWeights.begin(), usedWeights.end()); std::map<int, int> weightCompr; weightCompr[weightsVec[0]] = weightsVec[0]; weightCompr[weightsVec[1]] = weightsVec[1]; int factor = (weightsVec.size() > 7 ? 3 : 2); for (size_t i = 2; i < weightsVec.size(); ++i) weightCompr[weightsVec[i]] = weightsVec[(i - 2) / factor + 2]; for (std::vector<CCToken>::iterator tknIt = tokens.begin(); tknIt != tokens.end(); ++tknIt) { tknIt->weight = weightCompr[tknIt->weight]; } } } return tokens; }
bool EffectNyquist::PromptUser() { if (!SetXlispPath()) { return false; } if (mInteractive) { NyquistInputDialog dlog(wxGetTopLevelParent(NULL), -1, _("Nyquist Prompt"), _("Enter Nyquist Command: "), mInputCmd); dlog.CentreOnParent(); int result = dlog.ShowModal(); if (result == wxID_CANCEL) { return false; } /*if (result == eDebugID) { mDebug = true; }*/ mDebug = (result == eDebugID); // remember exact input in mInputCmd which will appear in the next // NyquistInputDialog. Copy to mCmd for possible embedding in // "function main() begin ... end": mCmd = mInputCmd = dlog.GetCommand(); // Is this LISP or SAL? Both allow comments. After comments, LISP // must begin with "(". Technically, a LISP expression could be a // symbol or number or string, etc., but these are not really // useful expressions. If the input begins with a symbol, number, // or string, etc., it is more likely an erroneous attempt to type // a SAL expression (which should probably begin with "return"), // so we will treat it as SAL. // this is a state machine to scan past LISP comments and white // space to find the first real character of LISP or SAL. Note // that #| ... |# style comments are not valid in SAL, so we do // not skip these. Instead, "#|" indicates LISP if found. // unsigned int i = 0; bool inComment = false; // handle "; ... \n" comments while (i < mCmd.Len()) { if (inComment) { inComment = (mCmd[i] != wxT('\n')); } else if (mCmd[i] == wxT(';')) { inComment = true; } else if (!wxIsspace(mCmd[i])) { break; // found the first non-comment, non-space character } i++; } // invariant: i == mCmd.Len() | // mCmd[i] is first non-comment, non-space character mIsSal = false; if (mCmd.Len() > i && mCmd[i] != wxT('(') && (mCmd[i] != wxT('#') || mCmd.Len() <= i + 1 || mCmd[i + 1] != wxT('|'))) { mIsSal = true; wxString cmdUp = mCmd.Upper(); int returnLoc = cmdUp.Find(wxT("RETURN")); if (returnLoc == wxNOT_FOUND) { wxMessageBox(_("Your code looks like SAL syntax, but there is no return statement. Either use a return statement such as\n\treturn s * 0.1\nfor SAL, or begin with an open parenthesis such as\n\t(mult s 0.1)\n for LISP."), _("Error in Nyquist code"), wxOK | wxCENTRE); return false; } } return true; } if (!mExternal) { if (mFileName.GetModificationTime().IsLaterThan(mFileModified)) { ParseFile(); mFileModified = mFileName.GetModificationTime(); } } if (mControls.GetCount() == 0) { return true; } for (unsigned int i = 0; i < mControls.GetCount(); i++) { NyqControl *ctrl = &mControls[i]; if (ctrl->type == NYQ_CTRL_STRING) { continue; } if (ctrl->val == UNINITIALIZED_CONTROL) { ctrl->val = GetCtrlValue(ctrl->valStr); } if (ctrl->type == NYQ_CTRL_CHOICE) { continue; } ctrl->low = GetCtrlValue(ctrl->lowStr); ctrl->high = GetCtrlValue(ctrl->highStr); if (ctrl->high < ctrl->low) { ctrl->high = ctrl->low + 1; } if (ctrl->val < ctrl->low) { ctrl->val = ctrl->low; } if (ctrl->val > ctrl->high) { ctrl->val = ctrl->high; } ctrl->ticks = 1000; if (ctrl->type == NYQ_CTRL_INT && (ctrl->high - ctrl->low < ctrl->ticks)) { ctrl->ticks = (int)(ctrl->high - ctrl->low); } } NyquistDialog dlog(mParent, -1, mName, mInfo, &mControls); dlog.CentreOnParent(); int result = dlog.ShowModal(); if (result == wxID_CANCEL) { return false; } /* if (result == eDebugID) { mDebug = true; } */ mDebug = (result == eDebugID); return true; }
wxHtmlTagsCache::wxHtmlTagsCache(const wxString& source) { m_Cache = new wxHtmlTagsCacheData; m_CachePos = 0; wxChar tagBuffer[256]; const wxString::const_iterator end = source.end(); for ( wxString::const_iterator pos = source.begin(); pos < end; ++pos ) { if (*pos != wxT('<')) continue; // possible tag start found: // don't cache comment tags if ( wxHtmlParser::SkipCommentTag(pos, end) ) continue; // Remember the starting tag position. wxString::const_iterator stpos = pos++; // And look for the ending one. int i; for ( i = 0; pos < end && i < (int)WXSIZEOF(tagBuffer) - 1 && *pos != wxT('>') && !wxIsspace(*pos); ++i, ++pos ) { tagBuffer[i] = (wxChar)wxToupper(*pos); } tagBuffer[i] = wxT('\0'); while (pos < end && *pos != wxT('>')) ++pos; if ( pos == end ) { // We didn't find a closing bracket, this is not a valid tag after // all. Notice that we need to roll back pos to avoid creating an // invalid iterator when "++pos" is done in the loop statement. --pos; continue; } // We have a valid tag, add it to the cache. size_t tg = Cache().size(); Cache().push_back(wxHtmlCacheItem()); Cache()[tg].Key = stpos; Cache()[tg].Name = new wxChar[i+1]; memcpy(Cache()[tg].Name, tagBuffer, (i+1)*sizeof(wxChar)); if ((stpos+1) < end && *(stpos+1) == wxT('/')) // ending tag: { Cache()[tg].type = wxHtmlCacheItem::Type_EndingTag; // find matching begin tag: for (i = tg; i >= 0; i--) { if ((Cache()[i].type == wxHtmlCacheItem::Type_NoMatchingEndingTag) && (wxStrcmp(Cache()[i].Name, tagBuffer+1) == 0)) { Cache()[i].type = wxHtmlCacheItem::Type_Normal; Cache()[i].End1 = stpos; Cache()[i].End2 = pos + 1; break; } } } else { Cache()[tg].type = wxHtmlCacheItem::Type_NoMatchingEndingTag; if (wxIsCDATAElement(tagBuffer)) { // store the orig pos in case we are missing the closing // tag (see below) const wxString::const_iterator old_pos = pos; bool foundCloseTag = false; // find next matching tag int tag_len = wxStrlen(tagBuffer); while (pos < end) { // find the ending tag while (pos + 1 < end && (*pos != '<' || *(pos+1) != '/')) ++pos; if (*pos == '<') ++pos; // see if it matches int match_pos = 0; while (pos < end && match_pos < tag_len ) { wxChar c = *pos; if ( c == '>' || c == '<' ) break; // cast to wxChar needed to suppress warning in // Unicode build if ((wxChar)wxToupper(c) == tagBuffer[match_pos]) { ++match_pos; } else if (c == wxT(' ') || c == wxT('\n') || c == wxT('\r') || c == wxT('\t')) { // need to skip over these } else { match_pos = 0; } ++pos; } // found a match if (match_pos == tag_len) { pos = pos - tag_len - 3; foundCloseTag = true; break; } else // keep looking for the closing tag { ++pos; } } if (!foundCloseTag) { // we didn't find closing tag; this means the markup // is incorrect and the best thing we can do is to // ignore the unclosed tag and continue parsing as if // it didn't exist: pos = old_pos; } } } } // ok, we're done, now we'll free .Name members of cache - we don't need it anymore: for ( wxHtmlTagsCacheData::iterator i = Cache().begin(); i != Cache().end(); ++i ) { wxDELETEA(i->Name); } }
long wxExecute( const wxString& command, int flags, wxProcess *process ) { wxCHECK_MSG( !command.empty(), 0, wxT("can't exec empty command") ); wxLogDebug(wxString(wxT("Launching: ")) + command); #if wxUSE_THREADS // fork() doesn't mix well with POSIX threads: on many systems the program // deadlocks or crashes for some reason. Probably our code is buggy and // doesn't do something which must be done to allow this to work, but I // don't know what yet, so for now just warn the user (this is the least we // can do) about it wxASSERT_MSG( wxThread::IsMain(), _T("wxExecute() can be called only from the main thread") ); #endif // wxUSE_THREADS int argc = 0; wxChar *argv[WXEXECUTE_NARGS]; wxString argument; const wxChar *cptr = command.c_str(); wxChar quotechar = wxT('\0'); // is arg quoted? bool escaped = false; // split the command line in arguments do { argument=wxT(""); quotechar = wxT('\0'); // eat leading whitespace: while ( wxIsspace(*cptr) ) cptr++; if ( *cptr == wxT('\'') || *cptr == wxT('"') ) quotechar = *cptr++; do { if ( *cptr == wxT('\\') && ! escaped ) { escaped = true; cptr++; continue; } // all other characters: argument += *cptr++; escaped = false; // have we reached the end of the argument? if ( (*cptr == quotechar && ! escaped) || (quotechar == wxT('\0') && wxIsspace(*cptr)) || *cptr == wxT('\0') ) { wxASSERT_MSG( argc < WXEXECUTE_NARGS, wxT("too many arguments in wxExecute") ); argv[argc] = new wxChar[argument.length() + 1]; wxStrcpy(argv[argc], argument.c_str()); argc++; // if not at end of buffer, swallow last character: if(*cptr) cptr++; break; // done with this one, start over } } while(*cptr); } while(*cptr); argv[argc] = NULL; long lRc; #if defined(__DARWIN__) // wxMacExecute only executes app bundles. // It returns an error code if the target is not an app bundle, thus falling // through to the regular wxExecute for non app bundles. lRc = wxMacExecute(argv, flags, process); if( lRc != ((flags & wxEXEC_SYNC) ? -1 : 0)) return lRc; #endif // do execute the command lRc = wxExecute(argv, flags, process); // clean up argc = 0; while( argv[argc] ) delete [] argv[argc++]; return lRc; }
wx28HtmlTagsCache::wx28HtmlTagsCache(const wxString& source) { const wxChar *src = source.c_str(); int lng = source.length(); wxChar tagBuffer[256]; m_Cache = NULL; m_CacheSize = 0; m_CachePos = 0; int pos = 0; while (pos < lng) { if (src[pos] == wxT('<')) // tag found: { if (m_CacheSize % CACHE_INCREMENT == 0) m_Cache = (wx28HtmlCacheItem*) realloc(m_Cache, (m_CacheSize + CACHE_INCREMENT) * sizeof(wx28HtmlCacheItem)); int tg = m_CacheSize++; int stpos = pos++; m_Cache[tg].Key = stpos; int i; for ( i = 0; pos < lng && i < (int)WXSIZEOF(tagBuffer) - 1 && src[pos] != wxT('>') && !wxIsspace(src[pos]); i++, pos++ ) { tagBuffer[i] = (wxChar)wxToupper(src[pos]); } tagBuffer[i] = wxT('\0'); m_Cache[tg].Name = new wxChar[i+1]; memcpy(m_Cache[tg].Name, tagBuffer, (i+1)*sizeof(wxChar)); while (pos < lng && src[pos] != wxT('>')) pos++; if (src[stpos+1] == wxT('/')) // ending tag: { m_Cache[tg].End1 = m_Cache[tg].End2 = -2; // find matching begin tag: for (i = tg; i >= 0; i--) if ((m_Cache[i].End1 == -1) && (wxStrcmp(m_Cache[i].Name, tagBuffer+1) == 0)) { m_Cache[i].End1 = stpos; m_Cache[i].End2 = pos + 1; break; } } else { m_Cache[tg].End1 = m_Cache[tg].End2 = -1; if (wxIsCDATAElement(tagBuffer)) { // store the orig pos in case we are missing the closing // tag (see below) wxInt32 old_pos = pos; bool foundCloseTag = false; // find next matching tag int tag_len = wxStrlen(tagBuffer); while (pos < lng) { // find the ending tag while (pos + 1 < lng && (src[pos] != '<' || src[pos+1] != '/')) ++pos; if (src[pos] == '<') ++pos; // see if it matches int match_pos = 0; while (pos < lng && match_pos < tag_len && src[pos] != '>' && src[pos] != '<') { // cast to wxChar needed to suppress warning in // Unicode build if ((wxChar)wxToupper(src[pos]) == tagBuffer[match_pos]) { ++match_pos; } else if (src[pos] == wxT(' ') || src[pos] == wxT('\n') || src[pos] == wxT('\r') || src[pos] == wxT('\t')) { // need to skip over these } else { match_pos = 0; } ++pos; } // found a match if (match_pos == tag_len) { pos = pos - tag_len - 3; foundCloseTag = true; break; } else // keep looking for the closing tag { ++pos; } } if (!foundCloseTag) { // we didn't find closing tag; this means the markup // is incorrect and the best thing we can do is to // ignore the unclosed tag and continue parsing as if // it didn't exist: pos = old_pos; } } } } pos++; } // ok, we're done, now we'll free .Name members of cache - we don't need it anymore: for (int i = 0; i < m_CacheSize; i++) { delete[] m_Cache[i].Name; m_Cache[i].Name = NULL; } }
void wxFileConfig::Parse(wxTextFile& file, bool bLocal) { const wxChar *pStart; const wxChar *pEnd; wxString strLine; size_t nLineCount = file.GetLineCount(); for ( size_t n = 0; n < nLineCount; n++ ) { strLine = file[n]; // add the line to linked list if ( bLocal ) LineListAppend(strLine); // skip leading spaces for ( pStart = strLine; wxIsspace(*pStart); pStart++ ) ; // skip blank/comment lines if ( *pStart == wxT('\0')|| *pStart == wxT(';') || *pStart == wxT('#') ) continue; if ( *pStart == wxT('[') ) { // a new group pEnd = pStart; while ( *++pEnd != wxT(']') ) { if ( *pEnd == wxT('\\') ) { // the next char is escaped, so skip it even if it is ']' pEnd++; } if ( *pEnd == wxT('\n') || *pEnd == wxT('\0') ) { // we reached the end of line, break out of the loop break; } } if ( *pEnd != wxT(']') ) { wxLogError(_("file '%s': unexpected character %c at line %d."), file.GetName(), *pEnd, n + 1); continue; // skip this line } // group name here is always considered as abs path wxString strGroup; pStart++; strGroup << wxCONFIG_PATH_SEPARATOR << FilterInEntryName(wxString(pStart, pEnd - pStart)); // will create it if doesn't yet exist SetPath(strGroup); if ( bLocal ) m_pCurrentGroup->SetLine(m_linesTail); // check that there is nothing except comments left on this line bool bCont = TRUE; while ( *++pEnd != wxT('\0') && bCont ) { switch ( *pEnd ) { case wxT('#'): case wxT(';'): bCont = FALSE; break; case wxT(' '): case wxT('\t'): // ignore whitespace ('\n' impossible here) break; default: wxLogWarning(_("file '%s', line %d: '%s' ignored after group header."), file.GetName(), n + 1, pEnd); bCont = FALSE; } } } else { // a key const wxChar *pEnd = pStart; while ( *pEnd && *pEnd != wxT('=') && !wxIsspace(*pEnd) ) { if ( *pEnd == wxT('\\') ) { // next character may be space or not - still take it because it's // quoted (unless there is nothing) pEnd++; if ( !*pEnd ) { // the error message will be given below anyhow break; } } pEnd++; } wxString strKey(FilterInEntryName(wxString(pStart, pEnd))); // skip whitespace while ( wxIsspace(*pEnd) ) pEnd++; if ( *pEnd++ != wxT('=') ) { wxLogError(_("file '%s', line %d: '=' expected."), file.GetName(), n + 1); } else { ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strKey); if ( pEntry == NULL ) { // new entry pEntry = m_pCurrentGroup->AddEntry(strKey, n); if ( bLocal ) pEntry->SetLine(m_linesTail); } else { if ( bLocal && pEntry->IsImmutable() ) { // immutable keys can't be changed by user wxLogWarning(_("file '%s', line %d: value for immutable key '%s' ignored."), file.GetName(), n + 1, strKey.c_str()); continue; } // the condition below catches the cases (a) and (b) but not (c): // (a) global key found second time in global file // (b) key found second (or more) time in local file // (c) key from global file now found in local one // which is exactly what we want. else if ( !bLocal || pEntry->IsLocal() ) { wxLogWarning(_("file '%s', line %d: key '%s' was first found at line %d."), file.GetName(), n + 1, strKey.c_str(), pEntry->Line()); if ( bLocal ) pEntry->SetLine(m_linesTail); } } // skip whitespace while ( wxIsspace(*pEnd) ) pEnd++; if ( GetStyle() & wxCONFIG_USE_NO_ESCAPE_CHARACTERS ) pEntry->SetValue(pEnd, FALSE /* read from file, without escapes */); else pEntry->SetValue(FilterInValue(pEnd), FALSE /* read from file, with escapes */); //pEntry->SetValue(FilterInValue(pEnd), FALSE /* read from file */); } } } }