Files
five/hbrtl/setcmd.go
Charles KWON OhJun 21fd9dc65c feat: SET DELETED filtering, SEEK/LOCATE/CONTINUE, SET command codegen
- skipFilter: skip deleted records in GoTop/GoBottom/Skip when SET DELETED ON
- hbrdd.IsSetDeleted callback: avoids circular import hbrdd→hbrtl
- Parser: capture ON/OFF for boolean SET commands (DELETED, EXACT, SOFTSEEK, etc.)
- Parser: capture TO expr for SET DATE/DECIMALS/EPOCH
- Gengo: emit proper t.Do() calls for 11 SET toggles + 3 value SETs
- stmtSet: was stub (skipToEOL), now calls parseSet()
- RTL: register 11 SET toggle functions (SETDELETED, SETEXACT, etc.)
- RTL: DBLOCATE/DBCONTINUE for sequential search
- RTL: DBSETFILTER/DBCLEARFILTER/DBFILTER
- PadL/PadR: support 3rd param fill character
- Area interface: added SetFound, SetLocate, LocateBlock, filter methods
- MemRDD: implements new Area interface methods
- Comprehensive PRG test: test_search.prg (7 test suites all pass)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 22:33:59 +09:00

278 lines
6.9 KiB
Go

// Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com)
// All rights reserved.
// SET command functions: SET EXACT, SET SOFTSEEK, SET DELETED, SET EXCLUSIVE,
// SET(_SET_xxx, lValue) pattern.
// Harbour: src/rtl/set.c — 47+ settings in HB_SET_ENUM.
package hbrtl
import (
"five/hbrdd"
"five/hbrt"
"sync"
)
// SET indices (Harbour HB_SET_ENUM compatible)
const (
SetExact = 1
SetFixed = 2
SetDecimals = 3
SetDateFmt = 4
SetEpoch = 5
SetPath = 6
SetDefault = 7
SetDeleted = 8
SetExclusive = 11
SetSoftSeek = 12
SetUnique = 13
SetCancel = 14
SetConfirm = 15
SetConsole = 16
SetAlternate = 17
SetDevice = 18
SetPrinter = 19
SetBell = 20
SetEscape = 21
SetInsert = 22
SetExit = 23
SetIntensity = 24
SetScoreB = 25
SetColorIdx = 26
SetCursorIdx = 27
SetWrap = 28
SetMessage = 29
)
var (
settings = map[int]hbrt.Value{
SetExact: hbrt.MakeBool(false),
SetFixed: hbrt.MakeBool(false),
SetDecimals: hbrt.MakeInt(2),
SetDeleted: hbrt.MakeBool(false),
SetExclusive: hbrt.MakeBool(true),
SetSoftSeek: hbrt.MakeBool(false),
SetUnique: hbrt.MakeBool(false),
SetCancel: hbrt.MakeBool(true),
SetConfirm: hbrt.MakeBool(false),
SetConsole: hbrt.MakeBool(true),
SetBell: hbrt.MakeBool(false),
SetEscape: hbrt.MakeBool(true),
SetInsert: hbrt.MakeBool(false),
SetExit: hbrt.MakeBool(false),
SetIntensity: hbrt.MakeBool(true),
SetWrap: hbrt.MakeBool(false),
}
setMu sync.Mutex
)
// SET(nSpecifier [, xNewValue]) → xOldValue
// Generic SET function matching Harbour's Set() function.
func SetFunc(t *hbrt.Thread) {
nParams := t.ParamCount()
t.Frame(nParams, 0)
defer t.EndProc()
nSet := t.Local(1).AsInt()
setMu.Lock()
defer setMu.Unlock()
old, exists := settings[nSet]
if !exists {
old = hbrt.MakeNil()
}
if nParams >= 2 && !t.Local(2).IsNil() {
settings[nSet] = t.Local(2)
}
t.RetVal(old)
}
// GetSetting returns a SET value (called internally).
func GetSetting(nSet int) hbrt.Value {
setMu.Lock()
defer setMu.Unlock()
v, ok := settings[nSet]
if !ok {
return hbrt.MakeNil()
}
return v
}
// GetSetDeleted returns SET DELETED state.
func GetSetDeleted() bool {
return GetSetting(SetDeleted).AsBool()
}
// GetSetExact returns SET EXACT state.
func GetSetExact() bool {
return GetSetting(SetExact).AsBool()
}
// GetSetSoftSeek returns SET SOFTSEEK state.
func GetSetSoftSeek() bool {
return GetSetting(SetSoftSeek).AsBool()
}
// GetSetDateFormat returns SET DATE format string.
func GetSetDateFormat() string {
v := GetSetting(SetDateFmt)
if v.IsString() {
return v.AsString()
}
return "mm/dd/yy"
}
// GetSetDecimals returns SET DECIMALS value.
func GetSetDecimals() int {
return GetSetting(SetDecimals).AsInt()
}
// GetSetEpoch returns SET EPOCH year.
func GetSetEpoch() int {
v := GetSetting(SetEpoch)
if v.IsNumeric() {
return v.AsInt()
}
return 1900
}
// --- Dedicated SET toggle functions ---
// Harbour: SET EXACT ON/OFF, SET DELETED ON/OFF, etc.
// SetExactFunc: SET(_SET_EXACT [, lNew]) → lOld
func SetExactFunc(t *hbrt.Thread) { setToggle(t, SetExact) }
// SetDeletedFunc: SET(_SET_DELETED [, lNew]) → lOld
func SetDeletedFunc(t *hbrt.Thread) { setToggle(t, SetDeleted) }
// SetSoftSeekFunc: SET(_SET_SOFTSEEK [, lNew]) → lOld
func SetSoftSeekFunc(t *hbrt.Thread) { setToggle(t, SetSoftSeek) }
// SetExclusiveFunc: SET(_SET_EXCLUSIVE [, lNew]) → lOld
func SetExclusiveFunc(t *hbrt.Thread) { setToggle(t, SetExclusive) }
// SetFixedFunc: SET(_SET_FIXED [, lNew]) → lOld
func SetFixedFunc(t *hbrt.Thread) { setToggle(t, SetFixed) }
// SetCancelFunc: SET(_SET_CANCEL [, lNew]) → lOld
func SetCancelFunc(t *hbrt.Thread) { setToggle(t, SetCancel) }
// SetBellFunc: SET(_SET_BELL [, lNew]) → lOld
func SetBellFunc(t *hbrt.Thread) { setToggle(t, SetBell) }
// SetConfirmFunc: SET(_SET_CONFIRM [, lNew]) → lOld
func SetConfirmFunc(t *hbrt.Thread) { setToggle(t, SetConfirm) }
// SetInsertFunc: SET(_SET_INSERT [, lNew]) → lOld
func SetInsertFunc(t *hbrt.Thread) { setToggle(t, SetInsert) }
// SetEscapeFunc: SET(_SET_ESCAPE [, lNew]) → lOld
func SetEscapeFunc(t *hbrt.Thread) { setToggle(t, SetEscape) }
// SetWrapFunc: SET(_SET_WRAP [, lNew]) → lOld
func SetWrapFunc(t *hbrt.Thread) { setToggle(t, SetWrap) }
// setToggle implements SET(n, lNew) → lOld for boolean settings
func setToggle(t *hbrt.Thread, setID int) {
nParams := t.ParamCount()
t.Frame(nParams, 0)
defer t.EndProc()
setMu.Lock()
defer setMu.Unlock()
old, ok := settings[setID]
if !ok {
old = hbrt.MakeBool(false)
}
if nParams >= 1 && !t.Local(1).IsNil() {
settings[setID] = t.Local(1)
}
t.RetVal(old)
}
// SetDateFunc: __SetDateFormat([cNew]) → cOld
func SetDateFunc(t *hbrt.Thread) {
nParams := t.ParamCount()
t.Frame(nParams, 0)
defer t.EndProc()
setMu.Lock()
defer setMu.Unlock()
old, ok := settings[SetDateFmt]
if !ok {
old = hbrt.MakeString("mm/dd/yy")
}
if nParams >= 1 && t.Local(1).IsString() {
dfmt := t.Local(1).AsString()
settings[SetDateFmt] = hbrt.MakeString(dfmt)
}
t.RetVal(old)
}
// SetDecimalsFunc: SET DECIMALS TO n
func SetDecimalsFunc(t *hbrt.Thread) {
nParams := t.ParamCount()
t.Frame(nParams, 0)
defer t.EndProc()
setMu.Lock()
defer setMu.Unlock()
old := settings[SetDecimals]
if nParams >= 1 && t.Local(1).IsNumeric() {
settings[SetDecimals] = t.Local(1)
}
t.RetVal(old)
}
// SetEpochFunc: SET EPOCH TO n
func SetEpochFunc(t *hbrt.Thread) {
nParams := t.ParamCount()
t.Frame(nParams, 0)
defer t.EndProc()
setMu.Lock()
defer setMu.Unlock()
old, ok := settings[SetEpoch]
if !ok {
old = hbrt.MakeInt(1900)
}
if nParams >= 1 && t.Local(1).IsNumeric() {
settings[SetEpoch] = t.Local(1)
}
t.RetVal(old)
}
// --- SET constants for PRG code (registered as RTL functions) ---
// _SET_EXACT etc. — return the SET index constant
func SetConstExact(t *hbrt.Thread) { t.Frame(0, 0); defer t.EndProc(); t.PushInt(SetExact); t.RetValue() }
func SetConstDeleted(t *hbrt.Thread) { t.Frame(0, 0); defer t.EndProc(); t.PushInt(SetDeleted); t.RetValue() }
func SetConstSoftSeek(t *hbrt.Thread) { t.Frame(0, 0); defer t.EndProc(); t.PushInt(SetSoftSeek); t.RetValue() }
func SetConstExclusive(t *hbrt.Thread) { t.Frame(0, 0); defer t.EndProc(); t.PushInt(SetExclusive); t.RetValue() }
func SetConstDateFmt(t *hbrt.Thread) { t.Frame(0, 0); defer t.EndProc(); t.PushInt(SetDateFmt); t.RetValue() }
func SetConstDecimals(t *hbrt.Thread) { t.Frame(0, 0); defer t.EndProc(); t.PushInt(SetDecimals); t.RetValue() }
func SetConstEpoch(t *hbrt.Thread) { t.Frame(0, 0); defer t.EndProc(); t.PushInt(SetEpoch); t.RetValue() }
// init registers default DATE format and EPOCH, and hooks into hbrdd.
func init() {
hbrdd.IsSetDeleted = GetSetDeleted
setMu.Lock()
if _, ok := settings[SetDateFmt]; !ok {
settings[SetDateFmt] = hbrt.MakeString("mm/dd/yy")
}
if _, ok := settings[SetEpoch]; !ok {
settings[SetEpoch] = hbrt.MakeInt(1900)
}
setMu.Unlock()
}