• docs/boolsrch.md src/sbbs3/boolsrch.c boolsrch.h boolsrch_test.cctrl/t

    From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Sun May 17 18:45:24 2026
    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) <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)