/* e_search.cpp * * Copyright (c) 1994-1996, Marko Macek * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. * */ #include "fte.h" int ParseSearchOption(int replace, char c, unsigned long &opt) { switch (c) { case 'a': opt |= SEARCH_ALL; break; // search all occurances case 'b': opt |= SEARCH_BLOCK; break; // search in block only case 'c': opt &= ~SEARCH_NEXT; break; // search from current position case 'd': opt |= SEARCH_DELETE; break; // delete found line case 'g': opt |= SEARCH_GLOBAL; break; // search globally case 'i': opt |= SEARCH_NCASE; break; // don't match case case 'j': opt |= SEARCH_JOIN; break; // join found line case 'r': opt |= SEARCH_BACK; break; // search reverse case 'w': opt |= SEARCH_WORDBEG | SEARCH_WORDEND; break; case '<': opt |= SEARCH_WORDBEG; break; case '>': opt |= SEARCH_WORDEND; break; case 'x': opt |= SEARCH_RE; break; // search using regexps default: if (!replace) return 0; switch (c) { case 'n': opt |= SEARCH_NASK; break; // don't ask before replacing default: return 0; } } return 1; } int UnquoteString(char *str) { char *s, *d; s = str; d = str; while (*s) { if (*s == '\\') { s++; if (*s == 0) return 0; } *d++ = *s++; } *d = 0; return 1; } int ParseSearchOptions(int replace, const char *str, unsigned long &Options) { const char *p = str; Options = SEARCH_NEXT; while (*p) { if (ParseSearchOption(replace, *p, Options) == 0) return 0; p++; } return 1; } int ParseSearchReplace(EBuffer *B, const char *str, int replace, SearchReplaceOptions &opt) { int where = 0; int len = 0; const char *p = str; memset((void *)&opt, 0, sizeof(opt)); if (p == 0) return 0; if (replace) { if (ParseSearchOptions(replace, BFS(B, BFS_DefFindReplaceOpt), opt.Options) == 0) return 0; opt.Options |= SEARCH_REPLACE; } else { if (ParseSearchOptions(replace, BFS(B, BFS_DefFindOpt), opt.Options) == 0) return 0; } while (*p) { switch (*p) { case '\\': if (where == 0) { opt.strSearch[len++] = *p++; if (*p == 0) return 0; opt.strSearch[len++] = *p++; } else if (where == 1) { opt.strReplace[len++] = *p++; if (*p == 0) return 0; opt.strReplace[len++] = *p++; } else return 0; break; case '/': where++; if (!replace && where == 1) where++; if (where == 2) opt.Options = SEARCH_NEXT; if (where > 2) return 0; len = 0; p++; break; default: if (where == 0) opt.strSearch[len++] = *p++; else if (where == 1) opt.strReplace[len++] = *p++; else { char c = *p; p++; if (ParseSearchOption(replace, c, opt.Options) == 0) return 0; } } } if (opt.Options & SEARCH_RE); else { if (UnquoteString(opt.strSearch) == 0) return 0; if (opt.Options & SEARCH_REPLACE) if (UnquoteString(opt.strReplace) == 0) return 0; } opt.ok = 1; return 1; } int EBuffer::FindStr(char *Data, int Len, int Options) { int LLen, Start, End; int C, L; PELine X; char *P; if (Options & SEARCH_RE) return 0; if (Len <= 0) return 0; if (Options & SEARCH_NOPOS) { C = Match.Col; L = Match.Row; } else { C = CP.Col; L = VToR(CP.Row); } if (Match.Row != -1) Draw(Match.Row, Match.Row); Match.Row = -1; Match.Col = -1; X = RLine(L); C = CharOffset(X, C); if (Options & SEARCH_NEXT) { int CC = MatchCount ? MatchCount : 1; if (Options & SEARCH_BACK) { C -= CC; if (C < 0) { if (L == 0) return 0; L--; X = RLine(L); C = X->Count; } } else { C += CC; if (C >= X->Count) { C = 0; L++; if (L == RCount) return 0; } } } MatchLen = 0; MatchCount = 0; if (Options & SEARCH_BLOCK) { if (Options & SEARCH_BACK) { if (BlockMode == bmStream) { if (L > BE.Row) { L = BE.Row; C = BE.Col; } if (L == BE.Row && C > BE.Col) C = BE.Col; } else { if (L >= BE.Row && BE.Row > 0) { L = BE.Row - 1; C = RLine(L)->Count; } if (BlockMode == bmColumn) if (L == BE.Row - 1 && C >= BE.Col) C = BE.Col; } } else { if (L < BB.Row) { L = BB.Row; C = 0; } if (L == BB.Row && C < BB.Col) C = BB.Col; } } while (1) { if (Options & SEARCH_BLOCK) { if (BlockMode == bmStream) { if (L > BE.Row || L < BB.Row) break; } else if (L >= BE.Row || L < BB.Row) break; } else if (L >= RCount || L < 0) break; X = RLine(L); LLen = X->Count; P = X->Chars; Start = 0; End = LLen; if (Options & SEARCH_BLOCK) { if (BlockMode == bmColumn) { Start = CharOffset(X, BB.Col); End = CharOffset(X, BE.Col); } else if (BlockMode == bmStream) { if (L == BB.Row) Start = CharOffset(X, BB.Col); if (L == BE.Row) End = CharOffset(X, BE.Col); } } if (Options & SEARCH_BACK) { if (C >= End - Len) C = End - Len; } else { if (C < Start) C = Start; } while (((!(Options & SEARCH_BACK)) && (C <= End - Len)) || ((Options & SEARCH_BACK) && (C >= Start))) { if ((!(Options & SEARCH_WORDBEG) || (C == 0) || (WGETBIT(Flags.WordChars, P[C - 1]) == 0)) && (!(Options & SEARCH_WORDEND) || (C + Len >= End) || (WGETBIT(Flags.WordChars, P[C + Len]) == 0)) && ((!(Options & SEARCH_NCASE) && (P[C] == Data[0]) && (memcmp(P + C, Data, Len) == 0)) || ((Options & SEARCH_NCASE) && (toupper(P[C]) == toupper(Data[0])) && (strnicmp(P + C, Data, Len) == 0))) /* && BOL | EOL */ ) { Match.Col = ScreenPos(X, C); Match.Row = L; MatchCount = Len; MatchLen = ScreenPos(X, C + Len) - Match.Col; if (!(Options & SEARCH_NOPOS)) { if (Options & SEARCH_CENTER) CenterPosR(Match.Col, Match.Row); else SetPosR(Match.Col, Match.Row); } Draw(L, L); return 1; } if (Options & SEARCH_BACK) C--; else C++; } if (Options & SEARCH_BACK) { L--; if (L >= 0) C = RLine(L)->Count; } else { C = 0; L++; } } //SetPos(OC, OL); return 0; } int EBuffer::FindRx(RxNode *Rx, int Options) { int LLen, Start, End; int C, L; char *P; PELine X; RxMatchRes b; if (!(Options & SEARCH_RE)) return 0; if (Options & SEARCH_BACK) { // not supported View->MView->Win->Choice(GPC_ERROR, "FindRx", 1, "O&K", "Reverse regexp search not supported."); return 0; } if (Rx == 0) return 0; if (Match.Row != -1) Draw(Match.Row, Match.Row); Match.Row = -1; Match.Col = -1; C = CP.Col; L = VToR(CP.Row); X = RLine(L); C = CharOffset(X, C); if (Options & SEARCH_NEXT) { int CC = MatchCount ? MatchCount : 1; if (Options & SEARCH_BACK) { C -= CC; if (Options & SEARCH_BLOCK) { if (C < BB.Col && L == BB.Row) return 0; L--; X = RLine(L); C = X->Count; if (BlockMode == bmColumn) if (BE.Col < C) C = BE.Col; } else { if (C < 0 && L == 0) return 0; L--; X = RLine(L); C = X->Count; } } else { C += CC; if (Options & SEARCH_BLOCK) { if (BlockMode == bmStream || BlockMode == bmLine) { if (C >= X->Count) { C = 0; L++; if (BlockMode == bmLine) { if (L == BE.Row) return 0; } else if (L == BE.Row && (C >= BE.Col || C >= X->Count)) return 0; } } else if (BlockMode == bmColumn) { if (C >= X->Count || C >= BE.Col) { C = BB.Col; L++; if (L == BE.Row) return 0; } } } else { if (C >= X->Count) { C = 0; L++; if (L == RCount) return 0; } } } } MatchLen = 0; MatchCount = 0; if (Options & SEARCH_BLOCK) { if (Options & SEARCH_BACK) { if (BlockMode == bmStream) { if (L > BE.Row) { L = BE.Row; C = BE.Col; } if (L == BE.Row && C > BE.Col) C = BE.Col; } else { if (L >= BE.Row && BE.Row > 0) { L = BE.Row - 1; C = RLine(L)->Count; } if (BlockMode == bmColumn) if (L == BE.Row - 1 && C >= BE.Col) C = BE.Col; } } else { if (L < BB.Row) { L = BB.Row; C = 0; } if (L == BB.Row && C < BB.Col) C = BB.Col; } } while (1) { if (Options & SEARCH_BLOCK) { if (BlockMode == bmStream) { if (L > BE.Row || L < BB.Row) break; } else if (L >= BE.Row || L < BB.Row) break; } else if (L >= RCount || L < 0) break; X = RLine(L); LLen = X->Count; P = X->Chars; Start = 0; End = LLen; if (Options & SEARCH_BLOCK) { if (BlockMode == bmColumn) { Start = CharOffset(X, BB.Col); End = CharOffset(X, BE.Col); } else if (BlockMode == bmStream) { if (L == BB.Row) Start = CharOffset(X, BB.Col); if (L == BE.Row) End = CharOffset(X, BE.Col); } if (End > LLen) End = LLen; } if (Options & SEARCH_BACK) { if (C >= End) C = End; } else { if (C < Start) C = Start; } if (Start <= End) { if (RxExec(Rx, P + Start, End - Start, P + C, &b, (Options & SEARCH_NCASE) ? 0 : RX_CASE) == 1) { C = ScreenPos(X, b.Open[0] + Start); Match.Col = C; Match.Row = L; MatchCount = b.Close[0] - b.Open[0]; MatchLen = ScreenPos(X, b.Close[0] + Start) - C; for (int mm = 0; mm < NSEXPS; mm++) { b.Open[mm] += Start; b.Close[mm] += Start; } MatchRes = b; if (!(Options & SEARCH_NOPOS)) { if (Options & SEARCH_CENTER) CenterPosR(C, L); else SetPosR(C, L); } Draw(L, L); return 1; } } C = 0; L++; } //SetPos(OC, OL); return 0; } int EBuffer::Find(SearchReplaceOptions &opt) { int slen = strlen(opt.strSearch); int Options = opt.Options; int rlen = strlen(opt.strReplace); RxNode *R = NULL; opt.resCount = -1; if (slen == 0) return 0; if (Options & SEARCH_BLOCK) { if (CheckBlock() == 0) return 0; } if (Options & SEARCH_RE) { R = RxCompile(opt.strSearch); if (R == 0) { View->MView->Win->Choice(GPC_ERROR, "Find", 1, "O&K", "Invalid regular expression."); return 0; } } if (Options & SEARCH_GLOBAL) { if (Options & SEARCH_BLOCK) { if (Options & SEARCH_BACK) { if (SetPosR(BE.Col, BE.Row) == 0) goto error; } else { if (SetPosR(BB.Col, BB.Row) == 0) goto error; } } else { if (Options & SEARCH_BACK) { if (RCount < 1) goto error; if (SetPosR(LineLen(RCount - 1), RCount - 1) == 0) goto error; } else { if (SetPosR(0, 0) == 0) goto error; } } } opt.resCount = 0; while (1) { if (Options & SEARCH_RE) { if (FindRx(R, Options) == 0) goto end; } else { if (FindStr(opt.strSearch, slen, Options) == 0) goto end; } opt.resCount++; if (opt.Options & SEARCH_REPLACE) { char ask = 'A'; if (!(Options & SEARCH_NASK)) { char ch; while (1) { Draw(VToR(CP.Row), 1); Redraw(); switch (View->MView->Win->Choice(0, "Replace", 5, "&Yes", "&All", "&Once", "&Skip", "&Cancel", "Replace with %s?", opt.strReplace)) { case 0: ch = 'Y'; break; case 1: ch = 'A'; break; case 2: ch = 'O'; break; case 3: ch = 'N'; break; case 4: case -1: default: ch = 'Q'; break; } if (ch == 'Y') { ask = 'Y'; goto ok_rep; } if (ch == 'N') { ask = 'N'; goto ok_rep; } if (ch == 'Q') { ask = 'Q'; goto ok_rep; } if (ch == 'A') { ask = 'A'; goto ok_rep; } if (ch == 'O') { ask = 'O'; goto ok_rep; } } ok_rep: if (ask == 'N') goto try_join; if (ask == 'Q') goto end; if (ask == 'A') Options |= SEARCH_NASK; } if (Options & SEARCH_RE) { PELine L = RLine(Match.Row); int P, R; char *PR = 0; int LR = 0; R = Match.Row; P = Match.Col; P = CharOffset(L, P); if (0 == RxReplace(opt.strReplace, L->Chars, L->Count, MatchRes, &PR, &LR)) { if (DelText(R, Match.Col, MatchLen) == 0) goto error; if (PR && LR > 0) if (InsText(R, Match.Col, LR, PR) == 0) goto error; if (PR) free(PR); rlen = LR; } } else { if (DelText(Match.Row, Match.Col, MatchLen) == 0) goto error; if (InsText(Match.Row, Match.Col, rlen, opt.strReplace) == 0) goto error; } if (!(Options & SEARCH_BACK)) { MatchLen = rlen; MatchCount = rlen; } if (ask == 'O') goto end; } try_join: if (Options & SEARCH_JOIN) { char ask = 'A'; if (!(Options & SEARCH_NASK)) { char ch; while (1) { Draw(VToR(CP.Row), 1); Redraw(); switch (View->MView->Win->Choice(0, "Join Line", 5, "&Yes", "&All", "&Once", "&Skip", "&Cancel", "Join lines %d and %d?", 1 + VToR(CP.Row), 1 + VToR(CP.Row) + 1)) { case 0: ch = 'Y'; break; case 1: ch = 'A'; break; case 2: ch = 'O'; break; case 3: ch = 'N'; break; case 4: case -1: default: ch = 'Q'; break; } if (ch == 'Y') { ask = 'Y'; goto ok_join; } if (ch == 'N') { ask = 'N'; goto ok_join; } if (ch == 'Q') { ask = 'Q'; goto ok_join; } if (ch == 'A') { ask = 'A'; goto ok_join; } if (ch == 'O') { ask = 'O'; goto ok_join; } } ok_join: if (ask == 'N') goto try_delete; if (ask == 'Q') goto end; if (ask == 'A') Options |= SEARCH_NASK; } if (JoinLine(Match.Row, Match.Col) == 0) goto error; if (ask == 'O') goto end; } try_delete: if (Options & SEARCH_DELETE) { char ask = 'A'; if (!(Options & SEARCH_NASK)) { char ch; while (1) { Draw(VToR(CP.Row), 1); Redraw(); switch (View->MView->Win->Choice(0, "Delete Line", 5, "&Yes", "&All", "&Once", "&Skip", "&Cancel", "Delete line %d?", VToR(CP.Row))) { case 0: ch = 'Y'; break; case 1: ch = 'A'; break; case 2: ch = 'O'; break; case 3: ch = 'N'; break; case 4: case -1: default: ch = 'Q'; break; } if (ch == 'Y') { ask = 'Y'; goto ok_delete; } if (ch == 'N') { ask = 'N'; goto ok_delete; } if (ch == 'Q') { ask = 'Q'; goto ok_delete; } if (ch == 'A') { ask = 'A'; goto ok_delete; } if (ch == 'O') { ask = 'O'; goto ok_delete; } } ok_delete: if (ask == 'N') goto next; if (ask == 'Q') goto end; if (ask == 'A') Options |= SEARCH_NASK; } if (Match.Row == RCount - 1) { if (DelText(Match.Row, 0, LineLen()) == 0) goto error; } else if (DelLine(Match.Row) == 0) goto error; if (ask == 'O') goto end; if (!(Options & SEARCH_ALL)) break; goto last; } next: if (!(Options & SEARCH_ALL)) break; Options |= SEARCH_NEXT; last: ; } end: // end of search if (R) RxFree(R); if (Options & SEARCH_ALL) Msg(S_INFO, "%d match(es) found.", opt.resCount); else { if (opt.resCount == 0) { Msg(S_INFO, "[%s] not found", opt.strSearch); return 0; } } return 1; error: if (R) { RxFree(R); } View->MView->Win->Choice(GPC_ERROR, "Find", 1, "O&K", "Error in search/replace."); return 0; } int EBuffer::CompleteWord() { #ifdef CONFIG_I_COMPLETE return View->MView->Win->ICompleteWord(View); #else PELine L = VLine(CP.Row), M; int C, P, X, P1, N, xlen, XL; EPoint O = CP; if (CP.Col == 0) return 0; if (SetPos(CP.Col, CP.Row) == 0) return 0; C = CP.Col; P = CharOffset(L, C); P1 = P; N = VToR(CP.Row); if (P > L->Count) return 0; if (P > 0) { while ((P > 0) && ((ChClass(L->Chars[P - 1]) == 1) || (L->Chars[P - 1] == '_'))) P--; if (P == P1) return 0; xlen = P1 - P; C = ScreenPos(L, P); Match.Row = N; Match.Col = C; //if (SetPos(C, CP.Row) == 0) return 0; //again: if (FindStr(L->Chars + P, xlen, SEARCH_BACK | SEARCH_NEXT | SEARCH_NOPOS | SEARCH_WORDBEG) == 1) { M = RLine(Match.Row); X = CharOffset(M, Match.Col); XL = X; //if ((XL > 0) && ((ChClass(M->Chars[XL - 1]) == 1) || (M->Chars[XL - 1] == '_'))) goto again; while ((XL < M->Count) && ((ChClass(M->Chars[XL]) == 1) || (M->Chars[XL] == '_'))) XL++; { char *pp = (char *)malloc(XL - X - xlen); if (pp) { memcpy(pp, M->Chars + X + xlen, XL - X - xlen); if (InsText(N, O.Col, XL - X - xlen, pp, 1) == 0) return 0; free(pp); } } if (SetPos(O.Col + XL - X - xlen, O.Row) == 0) return 0; Draw(Match.Row, Match.Row); Match.Row = -1; Match.Col = -1; MatchLen = 0; MatchCount = 0; return 1; } } if (Match.Row != -1) Draw(Match.Row, Match.Row); Match.Col = Match.Row = -1; MatchLen = 0; MatchCount = 0; return 0; #endif } int EBuffer::Search(ExState &State, char *aString, int Options, int /*CanResume*/) { char find[MAXSEARCH+1] = ""; int Case = BFI(this, BFI_MatchCase) ? 0 : SEARCH_NCASE; int Next = 0; int erc = 0; //int Changed; if (aString) strcpy(find, aString); else if (State.GetStrParam(View, find, sizeof(find)) == 0) if ((erc = View->MView->Win->GetStr("Find", sizeof(find), find, HIST_SEARCH)) == 0) return 0; if (strlen(find) == 0) return 0; if (erc == 2) Case ^= SEARCH_NCASE; //if (Changed == 0 && CanResume) // Next |= SEARCH_NEXT; LSearch.ok = 0; strcpy(LSearch.strSearch, find); LSearch.Options = Case | Next | (Options & ~SEARCH_NCASE); LSearch.ok = 1; if (Find(LSearch) == 0) return 0; return 1; } int EBuffer::SearchAgain(ExState &/*State*/, unsigned int Options) { if (LSearch.ok == 0) return 0; LSearch.Options |= SEARCH_NEXT; if ((Options & SEARCH_BACK) != (LSearch.Options & SEARCH_BACK)) LSearch.Options ^= SEARCH_BACK; if (Find(LSearch) == 0) return 0; return 1; } int EBuffer::SearchReplace(ExState &State, char *aString, char *aReplaceString, int Options) { char find[MAXSEARCH+1] = ""; char replace[MAXSEARCH+1] = ""; int Case = BFI(this, BFI_MatchCase) ? 0 : SEARCH_NCASE; if (aString) strcpy(find, aString); else if (State.GetStrParam(View, find, sizeof(find)) == 0) if (View->MView->Win->GetStr("Find", sizeof(find), find, HIST_SEARCH) == 0) return 0; if (strlen(find) == 0) return 0; if (aReplaceString) strcpy(replace, aReplaceString); else if (State.GetStrParam(View, replace, sizeof(replace)) == 0) if (View->MView->Win->GetStr("Replace", sizeof(replace), replace, HIST_SEARCH) == 0) return 0; LSearch.ok = 0; strcpy(LSearch.strSearch, find); strcpy(LSearch.strReplace, replace); LSearch.Options = Case | (Options & ~SEARCH_NCASE) | SEARCH_ALL | SEARCH_REPLACE; LSearch.ok = 1; if (Find(LSearch) == 0) return 0; return 1; } int EBuffer::Search(ExState &State) { return Search(State, 0, 0, 1); } int EBuffer::SearchB(ExState &State) { return Search(State, 0, SEARCH_BACK, 1); } int EBuffer::SearchRx(ExState &State) { return Search(State, 0, SEARCH_RE, 1); } int EBuffer::SearchAgain(ExState &State) { return SearchAgain(State, 0); } int EBuffer::SearchAgainB(ExState &State) { return SearchAgain(State, SEARCH_BACK); } int EBuffer::SearchReplace(ExState &State) { return SearchReplace(State, 0, 0, 0); } int EBuffer::SearchReplaceB(ExState &State) { return SearchReplace(State, 0, 0, SEARCH_BACK); } int EBuffer::SearchReplaceRx(ExState &State) { return SearchReplace(State, 0, 0, SEARCH_RE); } #ifdef CONFIG_OBJ_ROUTINE int EBuffer::ScanForRoutines() { RxNode *regx; int line; PELine L; RxMatchRes res; if (BFS(this, BFS_RoutineRegexp) == 0) { View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "No routine regexp."); return 0; } regx = RxCompile(BFS(this, BFS_RoutineRegexp)); if (regx == 0) { View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Failed to compile regexp '%s'", BFS(this, BFS_RoutineRegexp)); return 0; } if (rlst.Lines) { free(rlst.Lines); rlst.Lines = 0; } rlst.Lines = 0; rlst.Count = 0; Msg(S_BUSY, "Matching %s", BFS(this, BFS_RoutineRegexp)); for (line = 0; line < RCount; line++) { L = RLine(line); if (RxExec(regx, L->Chars, L->Count, L->Chars, &res) == 1) { rlst.Count++; rlst.Lines = (int *) realloc((void *) rlst.Lines, sizeof(int) * (rlst.Count | 0x1F)); rlst.Lines[rlst.Count - 1] = line; Msg(S_BUSY, "Routines: %d", rlst.Count); } } RxFree(regx); return 1; } #endif int EBuffer::ShowPosition() { int CLine, NLines; int CAct, NAct; int CColumn, NColumns; int CCharPos, NChars; #ifdef HEAPWALK unsigned long MemUsed = 0, MemFree = 0, BlkUsed = 0, BlkFree = 0, BigFree = 0, BigUsed = 0; #endif if (!View) return 0; CLine = CP.Row + 1; NLines = VCount; CAct = VToR(CP.Row) + 1; NAct = RCount; CColumn = CP.Col + 1; NColumns = LineLen(CP.Row); CCharPos = CharOffset(VLine(CP.Row), CP.Col) + 1; NChars = VLine(CP.Row)->Count; #ifdef HEAPWALK if (_heapchk() != _HEAPOK) { MemUsed = -1; } else { _HEAPINFO hi; hi._pentry = NULL; while (_heapwalk(&hi) == _HEAPOK) { if (hi._useflag == _USEDENTRY) { BlkUsed++; MemUsed += hi._size; if (hi._size > BigUsed) BigUsed = hi._size; //fprintf(stderr, "USED %d\n", hi._size); } else { BlkFree++; MemFree += hi._size; if (hi._size > BigFree) BigFree = hi._size; //fprintf(stderr, "FREE %d\n", hi._size); } } } #endif #ifdef CONFIG_UNDOREDO int NN = -1; if (US.UndoPtr > 0) NN = US.Top[US.UndoPtr - 1]; #endif Msg(S_INFO, #ifdef HEAPWALK "M%ld,%ld B%ld,%ld S%ld,%ld" #endif "L%d/%d G%d/%d/%d A%d/%d C%d/%d P%d/%d " #ifdef CONFIG_UNDOREDO "U%d/%d/%d " #endif "H%d/%d/%d", #ifdef HEAPWALK MemUsed, MemFree, BlkUsed, BlkFree, BigUsed, BigFree, #endif CLine, NLines, RGap, RCount, RAllocated, CAct, NAct, CColumn, NColumns, CCharPos, NChars, #ifdef CONFIG_UNDOREDO US.UndoPtr, US.Num, NN, #endif StartHilit, MinRedraw, MaxRedraw); return 1; } #ifdef CONFIG_BOOKMARKS int EBuffer::PlaceBookmark(char *Name, EPoint P) { int i; EBookmark *p; assert(P.Row >= 0 && P.Row < RCount && P.Col >= 0); for (i = 0; i < BMCount; i++) { if (strcmp(Name, BMarks[i].Name) == 0) { BMarks[i].BM = P; return 1; } } p = (EBookmark *) realloc(BMarks, sizeof (EBookmark) * (1 + BMCount)); if (p == 0) return 0; BMarks = p; BMarks[BMCount].Name = strdup(Name); BMarks[BMCount].BM = P; BMCount++; return 1; } int EBuffer::RemoveBookmark(char *Name) { int i; for (i = 0; i < BMCount; i++) { if (strcmp(Name, BMarks[i].Name) == 0) { free(BMarks[i].Name); memmove(BMarks + i, BMarks + i + 1, sizeof(EBookmark) * (BMCount - i - 1)); BMCount--; BMarks = (EBookmark *) realloc(BMarks, sizeof (EBookmark) * BMCount); return 1; } } View->MView->Win->Choice(GPC_ERROR, "RemoveBookmark", 1, "O&K", "Bookmark %s not found.", Name); return 0; } int EBuffer::GetBookmark(char *Name, EPoint &P) { for (int i = 0; i < BMCount; i++) if (strcmp(Name, BMarks[i].Name) == 0) { P = BMarks[i].BM; return 1; } return 0; } int EBuffer::GotoBookmark(char *Name) { for (int i = 0; i < BMCount; i++) if (strcmp(Name, BMarks[i].Name) == 0) { return CenterNearPosR(BMarks[i].BM.Col, BMarks[i].BM.Row); } View->MView->Win->Choice(GPC_ERROR, "GotoBookmark", 1, "O&K", "Bookmark %s not found.", Name); return 0; } #endif int EBuffer::GetMatchBrace(EPoint &M, int MinLine, int MaxLine, int show) { int StateLen; hsState *StateMap = 0; int Pos; PELine L = VLine(M.Row); int dir = 0; hsState State; char Ch1, Ch2; int CountX = 0; int StateRow = -1; M.Row = VToR(CP.Row); Pos = CharOffset(L, M.Col); if (Pos >= L->Count) return 0; switch(L->Chars[Pos]) { case '{': dir = +1; Ch1 = '{'; Ch2 = '}'; break; case '[': dir = +1; Ch1 = '['; Ch2 = ']'; break; case '<': dir = +1; Ch1 = '<'; Ch2 = '>'; break; case '(': dir = +1; Ch1 = '('; Ch2 = ')'; break; case '}': dir = -1; Ch1 = '}'; Ch2 = '{'; break; case ']': dir = -1; Ch1 = ']'; Ch2 = '['; break; case '>': dir = -1; Ch1 = '>'; Ch2 = '<'; break; case ')': dir = -1; Ch1 = ')'; Ch2 = '('; break; default: return 0; } StateMap = 0; if (GetMap(M.Row, &StateLen, &StateMap) == 0) return 0; State = StateMap[Pos]; StateRow = M.Row; while (M.Row >= MinLine && M.Row < MaxLine) { while (Pos >= 0 && Pos < L->Count) { if (L->Chars[Pos] == Ch1 || L->Chars[Pos] == Ch2) { // update syntax state if needed if (StateRow != M.Row) { free(StateMap); StateMap = 0; GetMap(M.Row, &StateLen, &StateMap); if (StateMap == 0) return 0; StateRow = M.Row; } if (StateMap[Pos] == State) { if (L->Chars[Pos] == Ch1) CountX++; if (L->Chars[Pos] == Ch2) CountX--; if (CountX == 0) { M.Col = ScreenPos(L, Pos); free(StateMap); return 1; } } } Pos += dir; } M.Row += dir; if (M.Row >= 0 && M.Row < RCount) { L = RLine(M.Row); Pos = (dir == 1) ? 0 : (L->Count - 1); } } if (StateMap) free(StateMap); if (show) Msg(S_INFO, "No match (%d missing).", CountX); return 0; } int EBuffer::MatchBracket() { EPoint M = CP; if (GetMatchBrace(M, 0, RCount, 1) == 1) return SetPosR(M.Col, M.Row); return 0; } int EBuffer::HilitMatchBracket() { EPoint M = CP; if (View == 0) return 0; int Min = VToR(GetVPort()->TP.Row); int Max = VToR(GetVPort()->TP.Row); Max += GetVPort()->Rows; if (Max >= RCount) Max = RCount; if (Min < 0) Min = 0; if (Max < Min) return 0; if (GetMatchBrace(M, Min, Max, 0) == 1) { Match = M; MatchLen = 1; MatchCount = 1; Draw(Match.Row, Match.Row); return 1; } return 0; } int EBuffer::SearchWord(int SearchFlags) { char word[MAXSEARCH + 1]; PELine L = VLine(CP.Row); int P, len = 0; int Case = BFI(this, BFI_MatchCase) ? 0 : SEARCH_NCASE; P = CharOffset(L, CP.Col); while ((P > 0) && ((ChClass(L->Chars[P - 1]) == 1) || (L->Chars[P - 1] == '_'))) P--; while (len < int(sizeof(word)) && P < L->Count && (ChClass(L->Chars[P]) == 1 || L->Chars[P] == '_')) word[len++] = L->Chars[P++]; word[len] = 0; if (len == 0) return 0; return FindStr(word, len, Case | SearchFlags | SEARCH_WORD); } int EBuffer::FindTagWord(ExState &State) { char word[MAXSEARCH + 1]; PELine L = VLine(CP.Row); int P, len = 0; P = CharOffset(L, CP.Col); while ((P > 0) && ((ChClass(L->Chars[P - 1]) == 1) || (L->Chars[P - 1] == '_'))) P--; while (len < int(sizeof(word)) && P < L->Count && (ChClass(L->Chars[P]) == 1 || L->Chars[P] == '_')) word[len++] = L->Chars[P++]; word[len] = 0; if (len == 0) { Msg(S_INFO, "No word at cursor."); return 0; } int j = 2; while (j--) { int i; i = TagFind(this, View, word); if (i > 0) return 1; else if (j && (i < 0)) { /* Try autoload tags */ if (View->ExecCommand(ExTagLoad, State) == 0) break; } else { Msg(S_INFO, "Tag '%s' not found.", word); break; } } return 0; }