(* Copyright 2021-2023 Anton Krotov This file is part of CEdit. CEdit is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. CEdit is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with CEdit. If not, see . *) MODULE Search; IMPORT CB := Clipboard, List, Utils, SYSTEM; CONST itemSize = 64; TYPE tBuffer = CB.tBuffer; tIdxTable = ARRAY 65536, 2 OF INTEGER; tPos* = POINTER TO RECORD (List.tItem) cnt*: INTEGER; pos*: ARRAY itemSize OF INTEGER END; VAR table: POINTER TO RECORD data: tIdxTable END; PROCEDURE _index (text: tBuffer; cs: BOOLEAN; VAR table: tIdxTable): tBuffer; VAR pChar, cnt, i: INTEGER; c: WCHAR; res: tBuffer; BEGIN pChar := text.dataPtr; cnt := CB.bufSize(text) DIV SYSTEM.SIZE(WCHAR); FOR i := 0 TO 65535 DO table[i, 1] := 0 END; i := cnt; WHILE i > 0 DO SYSTEM.GET(pChar, c); IF ~cs & Utils.lower(c) THEN SYSTEM.PUT(pChar, c) END; INC(table[ORD(c), 1]); INC(pChar, SYSTEM.SIZE(WCHAR)); DEC(i) END; res := CB.create(cnt*SYSTEM.SIZE(INTEGER)); table[0, 0] := res.dataPtr; FOR i := 1 TO 65535 DO table[i, 0] := table[i - 1, 0] + table[i - 1, 1]*SYSTEM.SIZE(INTEGER) END; pChar := text.dataPtr; i := 0; WHILE i < cnt DO SYSTEM.GET(pChar, c); SYSTEM.PUT(table[ORD(c), 0], i); INC(table[ORD(c), 0], SYSTEM.SIZE(INTEGER)); INC(pChar, SYSTEM.SIZE(WCHAR)); INC(i) END; FOR i := 0 TO 65535 DO DEC(table[i, 0], table[i, 1]*SYSTEM.SIZE(INTEGER)) END RETURN res END _index; PROCEDURE index* (text: tBuffer; cs: BOOLEAN): tBuffer; BEGIN IF table = NIL THEN NEW(table) END RETURN _index(text, cs, table.data) END index; PROCEDURE next* (VAR item: tPos; VAR i: INTEGER): INTEGER; VAR res: INTEGER; BEGIN IF (item # NIL) & (i >= item.cnt) THEN item := item.next(tPos); i := 0; END; IF (item # NIL ) & (i < item.cnt) THEN res := item.pos[i]; INC(i) ELSE res := -1 END RETURN res END next; PROCEDURE add* (list: List.tList; pos: INTEGER); VAR item: tPos; BEGIN item := list.last(tPos); IF (item = NIL) OR (item.cnt = itemSize) THEN NEW(item); item.cnt := 0; List.append(list, item) END; item.pos[item.cnt] := pos; INC(item.cnt) END add; PROCEDURE find* (text: tBuffer; s: ARRAY OF WCHAR; whole: BOOLEAN; list: List.tList; offset: INTEGER); VAR k, pos, n, i, x, prev_item_pos: INTEGER; c1, c2: WCHAR; flag: BOOLEAN; BEGIN ASSERT(table # NIL); n := LENGTH(s); i := 0; WHILE (i < n) & whole DO whole := Utils.isWordChar(s[i]); INC(i) END; k := table.data[ORD(s[0]), 1]; pos := table.data[ORD(s[0]), 0]; prev_item_pos := 0; WHILE k > 0 DO SYSTEM.GET(pos, x); IF Utils.streq(text.dataPtr + x*SYSTEM.SIZE(WCHAR), SYSTEM.ADR(s[0]), n) THEN flag := whole; IF flag THEN IF x > 0 THEN SYSTEM.GET(text.dataPtr + (x - 1)*SYSTEM.SIZE(WCHAR), c1); ELSE c1 := 0X END; SYSTEM.GET(text.dataPtr + (x + n)*SYSTEM.SIZE(WCHAR), c2); flag := Utils.isWordChar(c1) OR Utils.isWordChar(c2) END; IF ~flag & (x >= prev_item_pos) THEN prev_item_pos := x + n; add(list, x + offset) END END; INC(pos, SYSTEM.SIZE(INTEGER)); DEC(k) END END find; PROCEDURE close*; BEGIN IF table # NIL THEN DISPOSE(table) END END close; BEGIN table := NIL END Search.