Subj : docs/boolsrch.md src/sbbs3/boolsrch.c boolsrch.h boolsrch_test.cctrl/t To : Git commit to main/sbbs/master From : Rob Swindell (on Windows 11) Date : Sun May 17 2026 18:45:24 https://gitlab.synchro.net/main/sbbs/-/commit/64cf7e3d7f7a26349f1e009a Added Files: docs/boolsrch.md src/sbbs3/boolsrch.c boolsrch.h boolsrch_test.c Modified Files: ctrl/text.dat exec/load/text.js src/sbbs3/listfile.cpp objects.mk prntfile.cpp readmail.cpp readmsgs.cpp sbbs.jsdocs.vcxproj sbbs.vcxproj scandirs.cpp scansubs.cpp text.h text_defaults.c text_id.c Log Message: boolsrch: add boolean text-search engine (issue #1139) PCBoard/Wildcat-compatible boolean search syntax (AND/OR/NOT with parens, quoted phrases for whole-word match) for the four "Text to search for" prompts: message-base scan/F-find, private mail / search, file-listing search, and the less-style file pager. Bare-word queries keep their current case-insensitive substring semantics, so existing usage is unchanged; the new operators unlock multi-term searches that the old strcasestr-only code couldn't express. New engine (src/sbbs3/boolsrch.[ch], one TU): bool_expr_compile() parses query into AST, malloc'd errmsg on fail bool_expr_match() evaluate against a single haystack bool_expr_match_fields() evaluate against N fields (term hits doc if it appears in ANY field) - the shape callers want for scanning subj/body/tags or name/desc/tags/ author bool_expr_free() frees the compiled expression tree Recursive-descent parser, precedence NOT > AND > OR, supports both symbol (& | !) and keyword (AND OR NOT, case-insens, whole-word) forms. Quoted "..." phrases apply a word-boundary check at each side that contains no whitespace inside the quotes - so "TEST" won't match TESTING/BACKTEST while " TEST " is pure substring (escape hatch). Implicit AND is inserted before ! / NOT (Wildcat's "(windows|DOS) & (modem|comm) !OS/2" idiom). Wired through: readmsgs.cpp scanposts, searchposts (F find at scan and read-loop) listfile.cpp listfiles (FL_FIND across name/desc/extdesc/tags/author) prntfile.cpp printfile() P_SEEK / and n search readmail.cpp searchmail / at the mail read prompt scansubs.cpp getstr buffer raised from 40 to 120 for boolean queries scandirs.cpp same Engine compiles the expression once per scan and reuses it across every document - no per-record parsing cost. Malformed queries print the new text.dat string InvalidSearchExpression (#948) and return cleanly to the prompt; pre-existing stale defaults for SeekPrompt (#944) and SeekHelp (#947) were re-emitted by textgen at the same time. Standalone unit test (src/sbbs3/boolsrch_test.c, TU-include of boolsrch.c) covers 95 cases: precedence, parens, quoting + whitespace- boundary suppression, keyword-vs-substring discrimination (BANDIT not split on AND), implicit AND, syntax errors, multi-field matching. Public API is exactly the four entry points above; diagnostic helpers (describe/is_simple/simple_text) stay file-local. User-facing docs at docs/boolsrch.md for later wiki import. Co-Authored-By: Claude Opus 4.7 (1M context) --- þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net .